diff --git a/src/applications/repository/management/PhabricatorRepositoryManagementImportingWorkflow.php b/src/applications/repository/management/PhabricatorRepositoryManagementImportingWorkflow.php index acb533999b..7e814fc723 100644 --- a/src/applications/repository/management/PhabricatorRepositoryManagementImportingWorkflow.php +++ b/src/applications/repository/management/PhabricatorRepositoryManagementImportingWorkflow.php @@ -1,87 +1,91 @@ setName('importing') ->setExamples('**importing** __repository__ ...') ->setSynopsis( pht( 'Show commits in __repository__ which are still importing.')) ->setArguments( array( array( 'name' => 'simple', 'help' => pht('Show simpler output.'), ), array( 'name' => 'repos', 'wildcard' => true, ), )); } public function execute(PhutilArgumentParser $args) { $repos = $this->loadRepositories($args, 'repos'); if (!$repos) { throw new PhutilArgumentUsageException( pht( 'Specify one or more repositories to find importing commits for.')); } $repos = mpull($repos, null, 'getID'); $table = new PhabricatorRepositoryCommit(); $conn_r = $table->establishConnection('r'); $rows = queryfx_all( $conn_r, 'SELECT repositoryID, commitIdentifier, importStatus FROM %T - WHERE repositoryID IN (%Ld) AND (importStatus & %d) != %d', + WHERE repositoryID IN (%Ld) + AND (importStatus & %d) != %d + AND (importStatus & %d) != %d', $table->getTableName(), array_keys($repos), PhabricatorRepositoryCommit::IMPORTED_ALL, - PhabricatorRepositoryCommit::IMPORTED_ALL); + PhabricatorRepositoryCommit::IMPORTED_ALL, + PhabricatorRepositoryCommit::IMPORTED_UNREACHABLE, + PhabricatorRepositoryCommit::IMPORTED_UNREACHABLE); $console = PhutilConsole::getConsole(); if ($rows) { foreach ($rows as $row) { $repo = $repos[$row['repositoryID']]; $identifier = $row['commitIdentifier']; $console->writeOut('%s', $repo->formatCommitName($identifier)); if (!$args->getArg('simple')) { $status = $row['importStatus']; $need = array(); if (!($status & PhabricatorRepositoryCommit::IMPORTED_MESSAGE)) { $need[] = pht('Message'); } if (!($status & PhabricatorRepositoryCommit::IMPORTED_CHANGE)) { $need[] = pht('Change'); } if (!($status & PhabricatorRepositoryCommit::IMPORTED_OWNERS)) { $need[] = pht('Owners'); } if (!($status & PhabricatorRepositoryCommit::IMPORTED_HERALD)) { $need[] = pht('Herald'); } $console->writeOut(' %s', implode(', ', $need)); } $console->writeOut("\n"); } } else { $console->writeErr( "%s\n", pht('No importing commits found.')); } return 0; } } diff --git a/src/applications/repository/management/PhabricatorRepositoryManagementUpdateWorkflow.php b/src/applications/repository/management/PhabricatorRepositoryManagementUpdateWorkflow.php index f435861c60..1b52a7c0e4 100644 --- a/src/applications/repository/management/PhabricatorRepositoryManagementUpdateWorkflow.php +++ b/src/applications/repository/management/PhabricatorRepositoryManagementUpdateWorkflow.php @@ -1,181 +1,185 @@ verbose = $verbose; return $this; } public function getVerbose() { return $this->verbose; } protected function didConstruct() { $this ->setName('update') ->setExamples('**update** [options] __repository__') ->setSynopsis( pht( 'Update __repository__. This performs the __pull__, __discover__, '. '__refs__ and __mirror__ operations and is primarily an internal '. 'workflow.')) ->setArguments( array( array( 'name' => 'verbose', 'help' => pht('Show additional debugging information.'), ), array( 'name' => 'no-discovery', 'help' => pht('Do not perform discovery.'), ), array( 'name' => 'repos', 'wildcard' => true, ), )); } public function execute(PhutilArgumentParser $args) { $this->setVerbose($args->getArg('verbose')); $console = PhutilConsole::getConsole(); $repos = $this->loadLocalRepositories($args, 'repos'); if (count($repos) !== 1) { throw new PhutilArgumentUsageException( pht('Specify exactly one repository to update.')); } $repository = head($repos); try { id(new PhabricatorRepositoryPullEngine()) ->setRepository($repository) ->setVerbose($this->getVerbose()) ->pullRepository(); $no_discovery = $args->getArg('no-discovery'); if ($no_discovery) { return 0; } // TODO: It would be nice to discover only if we pulled something, but // this isn't totally trivial. It's slightly more complicated with // hosted repositories, too. $repository->writeStatusMessage( PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE, null); $this->discoverRepository($repository); $this->checkIfRepositoryIsFullyImported($repository); $this->updateRepositoryRefs($repository); $this->mirrorRepository($repository); $repository->writeStatusMessage( PhabricatorRepositoryStatusMessage::TYPE_FETCH, PhabricatorRepositoryStatusMessage::CODE_OKAY); } catch (DiffusionDaemonLockException $ex) { // If we miss a pull or discover because some other process is already // doing the work, just bail out. echo tsprintf( "%s\n", $ex->getMessage()); return 0; } catch (Exception $ex) { $repository->writeStatusMessage( PhabricatorRepositoryStatusMessage::TYPE_FETCH, PhabricatorRepositoryStatusMessage::CODE_ERROR, array( 'message' => pht( 'Error updating working copy: %s', $ex->getMessage()), )); throw $ex; } echo tsprintf( "%s\n", pht( 'Updated repository "%s".', $repository->getDisplayName())); return 0; } private function discoverRepository(PhabricatorRepository $repository) { $refs = id(new PhabricatorRepositoryDiscoveryEngine()) ->setRepository($repository) ->setVerbose($this->getVerbose()) ->discoverCommits(); return (bool)count($refs); } private function mirrorRepository(PhabricatorRepository $repository) { try { id(new PhabricatorRepositoryMirrorEngine()) ->setRepository($repository) ->pushToMirrors(); } catch (Exception $ex) { // TODO: We should report these into the UI properly, but for now just // complain. These errors are much less severe than pull errors. $proxy = new PhutilProxyException( pht( 'Error while pushing "%s" repository to mirrors.', $repository->getMonogram()), $ex); phlog($proxy); } } private function updateRepositoryRefs(PhabricatorRepository $repository) { id(new PhabricatorRepositoryRefEngine()) ->setRepository($repository) ->updateRefs(); } private function checkIfRepositoryIsFullyImported( PhabricatorRepository $repository) { // Check if the repository has the "Importing" flag set. We want to clear // the flag if we can. $importing = $repository->getDetail('importing'); if (!$importing) { // This repository isn't marked as "Importing", so we're done. return; } - // Look for any commit which hasn't imported. + // Look for any commit which is reachable and hasn't imported. $unparsed_commit = queryfx_one( $repository->establishConnection('r'), - 'SELECT * FROM %T WHERE repositoryID = %d AND (importStatus & %d) != %d + 'SELECT * FROM %T WHERE repositoryID = %d + AND (importStatus & %d) != %d + AND (importStatus & %d) != %d LIMIT 1', id(new PhabricatorRepositoryCommit())->getTableName(), $repository->getID(), PhabricatorRepositoryCommit::IMPORTED_ALL, - PhabricatorRepositoryCommit::IMPORTED_ALL); + PhabricatorRepositoryCommit::IMPORTED_ALL, + PhabricatorRepositoryCommit::IMPORTED_UNREACHABLE, + PhabricatorRepositoryCommit::IMPORTED_UNREACHABLE); if ($unparsed_commit) { // We found a commit which still needs to import, so we can't clear the // flag. return; } // Clear the "importing" flag. $repository->openTransaction(); $repository->beginReadLocking(); $repository = $repository->reload(); $repository->setDetail('importing', false); $repository->save(); $repository->endReadLocking(); $repository->saveTransaction(); } }