#!/usr/bin/env php setSynopsis(<<parseStandardArguments(); $args->parse( array( // what array( 'name' => 'revision', 'wildcard' => true, ), array( 'name' => 'all', 'param' => 'callsign or phid', 'help' => 'Reparse all commits in the specified repository. This '. 'mode queues parsers into the task queue; you must run '. 'taskmasters to actually do the parses. Use with '. '__--force-local__ to run the tasks locally instead of '. 'with taskmasters.', ), array( 'name' => 'min-date', 'param' => 'date', 'help' => 'When used with __--all__, this will restrict to '. 'reparsing only the commits that are newer than __date__.', ), // which parts array( 'name' => 'message', 'help' => 'Reparse commit messages.', ), array( 'name' => 'change', 'help' => 'Reparse changes.', ), array( 'name' => 'herald', 'help' => 'Reevaluate Herald rules (may send huge amounts of email!)', ), array( 'name' => 'owners', 'help' => 'Reevaluate related commits for owners packages (may '. 'delete existing relationship entries between your '. 'package and some old commits!)', ), // misc options array( 'name' => 'force', 'short' => 'f', 'help' => 'Act noninteractively, without prompting.', ), array( 'name' => 'force-local', 'help' => 'Only used with __--all__, use this to run the tasks '. 'locally instead of deferring them to taskmaster daemons.', ), )); $all_from_repo = $args->getArg('all'); $reparse_message = $args->getArg('message'); $reparse_change = $args->getArg('change'); $reparse_herald = $args->getArg('herald'); $reparse_owners = $args->getArg('owners'); $reparse_what = $args->getArg('revision'); $force = $args->getArg('force'); $force_local = $args->getArg('force-local'); $min_date = $args->getArg('min-date'); if (count($reparse_what) > 1 || !($all_from_repo xor count($reparse_what))) { usage("Specify a commit or repository to reparse."); } if ($args->getArg('trace')) { PhutilServiceProfiler::installEchoListener(); } if (!$reparse_message && !$reparse_change && !$reparse_herald && !$reparse_owners) { usage("Specify what information to reparse with --message, --change, ". "--herald, and/or --owners"); } if ($reparse_owners && !$force) { echo phutil_console_wrap( "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('Are you ready to continue?')) { echo "Cancelled.\n"; exit(1); } } $commits = array(); if ($all_from_repo) { $repository = id(new PhabricatorRepository())->loadOneWhere( 'callsign = %s OR phid = %s', $all_from_repo, $all_from_repo); if (!$repository) { throw new Exception("Unknown repository {$all_from_repo}!"); } $constraint = ''; if ($min_date) { $table = new PhabricatorRepositoryCommit(); $conn_r = $table->establishConnection('r'); $constraint = qsprintf( $conn_r, 'AND epoch > unix_timestamp(%s)', $min_date); } $commits = id(new PhabricatorRepositoryCommit())->loadAllWhere( 'repositoryID = %d %Q', $repository->getID(), $constraint); if (!$commits) { throw new Exception("No commits have been discovered in that repository!"); } $callsign = $repository->getCallsign(); } else { $matches = null; if (!preg_match('/r([A-Z]+)([a-z0-9]+)/', $reparse_what, $matches)) { throw new Exception("Can't parse commit identifier!"); } $callsign = $matches[1]; $commit_identifier = $matches[2]; $repository = id(new PhabricatorRepository())->loadOneWhere( 'callsign = %s', $callsign); if (!$repository) { throw new Exception("No repository with callsign '{$callsign}'!"); } $commit = id(new PhabricatorRepositoryCommit())->loadOneWhere( 'repositoryID = %d AND commitIdentifier = %s', $repository->getID(), $commit_identifier); if (!$commit) { throw new Exception( "No matching commit '{$commit_identifier}' in repository '{$callsign}'. ". "(For git and mercurial repositories, you must specify the entire ". "commit hash.)"); } $commits = array($commit); } if ($all_from_repo && !$force_local) { echo phutil_console_format( '**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.'); echo "\n\n"; echo "QUEUEING TASKS (".number_format(count($commits))." Commits):\n"; } $tasks = array(); foreach ($commits as $commit) { $classes = array(); switch ($repository->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: if ($reparse_message) { $classes[] = 'PhabricatorRepositoryGitCommitMessageParserWorker'; } if ($reparse_change) { $classes[] = 'PhabricatorRepositoryGitCommitChangeParserWorker'; } break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: if ($reparse_message) { $classes[] = 'PhabricatorRepositoryMercurialCommitMessageParserWorker'; } if ($reparse_change) { $classes[] = 'PhabricatorRepositoryMercurialCommitChangeParserWorker'; } break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: if ($reparse_message) { $classes[] = 'PhabricatorRepositorySvnCommitMessageParserWorker'; } if ($reparse_change) { $classes[] = 'PhabricatorRepositorySvnCommitChangeParserWorker'; } break; } if ($reparse_herald) { $classes[] = 'PhabricatorRepositoryCommitHeraldWorker'; } if ($reparse_owners) { $classes[] = 'PhabricatorRepositoryCommitOwnersWorker'; } $spec = array( 'commitID' => $commit->getID(), 'only' => true, ); if ($all_from_repo && !$force_local) { foreach ($classes as $class) { $task = new PhabricatorWorkerTask(); $task->setTaskClass($class); $task->setData($spec); $task->save(); $commit_name = 'r'.$callsign.$commit->getCommitIdentifier(); echo " Queued '{$class}' for commit '{$commit_name}'.\n"; } } else { foreach ($classes as $class) { $worker = newv($class, array($spec)); echo "Running '{$class}'...\n"; $worker->doWork(); } } } echo "\nDone.\n"; function usage($message) { echo phutil_console_format( '**Usage Exception:** '.$message."\n"); exit(1); }