From 02d7bb8604f3baecc25177f51814fa8d5a022692 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 16 Jun 2016 08:43:52 -0700 Subject: [PATCH] Add "bin/repository mark-reachable" for fixing commit reachability flags Summary: Ref T9028. This corrects the reachability of existing commits in a repository. In particular, it can be used to mark deleted commits as unreachable. Test Plan: - Ran it on a bad repository, with bad args, etc. - Ran it on a clean repo, got no changes. - Marked a reachable commit as unreachable, ran script, got it marked reachable. - Started deleting tags and branches from the local working copy while running the script, saw greater parts of the repository get marked unreachable. - Pulled repository again, everything automatically revived. Reviewers: chad Reviewed By: chad Maniphest Tasks: T9028 Differential Revision: https://secure.phabricator.com/D16132 --- src/__phutil_library_map__.php | 2 + .../daemon/PhabricatorGitGraphStream.php | 16 ++- ...ositoryManagementMarkReachableWorkflow.php | 103 ++++++++++++++++++ .../storage/PhabricatorRepositoryCommit.php | 39 +++++-- 4 files changed, 148 insertions(+), 12 deletions(-) create mode 100644 src/applications/repository/management/PhabricatorRepositoryManagementMarkReachableWorkflow.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 79e7ebf8e5..c4a590fb2b 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3263,6 +3263,7 @@ phutil_register_library_map(array( 'PhabricatorRepositoryManagementListWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListWorkflow.php', 'PhabricatorRepositoryManagementLookupUsersWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementLookupUsersWorkflow.php', 'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMarkImportedWorkflow.php', + 'PhabricatorRepositoryManagementMarkReachableWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMarkReachableWorkflow.php', 'PhabricatorRepositoryManagementMirrorWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMirrorWorkflow.php', 'PhabricatorRepositoryManagementMovePathsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMovePathsWorkflow.php', 'PhabricatorRepositoryManagementParentsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementParentsWorkflow.php', @@ -8052,6 +8053,7 @@ phutil_register_library_map(array( 'PhabricatorRepositoryManagementListWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementLookupUsersWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'PhabricatorRepositoryManagementWorkflow', + 'PhabricatorRepositoryManagementMarkReachableWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementMirrorWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementMovePathsWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementParentsWorkflow' => 'PhabricatorRepositoryManagementWorkflow', diff --git a/src/applications/repository/daemon/PhabricatorGitGraphStream.php b/src/applications/repository/daemon/PhabricatorGitGraphStream.php index 334213048e..669cf9c105 100644 --- a/src/applications/repository/daemon/PhabricatorGitGraphStream.php +++ b/src/applications/repository/daemon/PhabricatorGitGraphStream.php @@ -11,14 +11,20 @@ final class PhabricatorGitGraphStream public function __construct( PhabricatorRepository $repository, - $start_commit) { + $start_commit = null) { $this->repository = $repository; - $future = $repository->getLocalCommandFuture( - 'log --format=%s %s --', - '%H%x01%P%x01%ct', - $start_commit); + if ($start_commit !== null) { + $future = $repository->getLocalCommandFuture( + 'log --format=%s %s --', + '%H%x01%P%x01%ct', + $start_commit); + } else { + $future = $repository->getLocalCommandFuture( + 'log --format=%s --all --', + '%H%x01%P%x01%ct'); + } $this->iterator = new LinesOfALargeExecFuture($future); $this->iterator->setDelimiter("\n"); diff --git a/src/applications/repository/management/PhabricatorRepositoryManagementMarkReachableWorkflow.php b/src/applications/repository/management/PhabricatorRepositoryManagementMarkReachableWorkflow.php new file mode 100644 index 0000000000..84dea48948 --- /dev/null +++ b/src/applications/repository/management/PhabricatorRepositoryManagementMarkReachableWorkflow.php @@ -0,0 +1,103 @@ +setName('mark-reachable') + ->setExamples('**mark-reachable** [__options__] __repository__ ...') + ->setSynopsis( + pht( + 'Rebuild "unreachable" flags for commits in __repository__.')) + ->setArguments( + array( + 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 correct reachability status '. + 'for.')); + } + + foreach ($repos as $repo) { + $this->markReachable($repo); + } + + echo tsprintf( + "%s\n", + pht( + 'Examined %s commits already in the correct state.', + new PhutilNumber($this->untouchedCount))); + + echo tsprintf( + "%s\n", + pht('Done.')); + + return 0; + } + + private function markReachable(PhabricatorRepository $repository) { + if (!$repository->isGit()) { + throw new PhutilArgumentUsageException( + pht( + 'Only Git repositories are supported, this repository ("%s") is '. + 'not a Git repository.', + $repository->getDisplayName())); + } + + $viewer = $this->getViewer(); + + $commits = id(new DiffusionCommitQuery()) + ->setViewer($viewer) + ->withRepository($repository) + ->execute(); + + $flag = PhabricatorRepositoryCommit::IMPORTED_UNREACHABLE; + + $graph = new PhabricatorGitGraphStream($repository); + foreach ($commits as $commit) { + $identifier = $commit->getCommitIdentifier(); + + try { + $graph->getCommitDate($identifier); + $unreachable = false; + } catch (Exception $ex) { + $unreachable = true; + } + + // The commit has proper reachability, so do nothing. + if ($commit->isUnreachable() === $unreachable) { + $this->untouchedCount++; + continue; + } + + if ($unreachable) { + echo tsprintf( + "%s: %s\n", + $commit->getMonogram(), + pht('Marking commit unreachable.')); + + $commit->writeImportStatusFlag($flag); + } else { + echo tsprintf( + "%s: %s\n", + $commit->getMonogram(), + pht('Marking commit reachable.')); + + $commit->clearImportStatusFlag($flag); + } + } + } + +} diff --git a/src/applications/repository/storage/PhabricatorRepositoryCommit.php b/src/applications/repository/storage/PhabricatorRepositoryCommit.php index ec5d346302..ae43c67416 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryCommit.php +++ b/src/applications/repository/storage/PhabricatorRepositoryCommit.php @@ -64,13 +64,38 @@ final class PhabricatorRepositoryCommit } public function writeImportStatusFlag($flag) { - queryfx( - $this->establishConnection('w'), - 'UPDATE %T SET importStatus = (importStatus | %d) WHERE id = %d', - $this->getTableName(), - $flag, - $this->getID()); - $this->setImportStatus($this->getImportStatus() | $flag); + return $this->adjustImportStatusFlag($flag, true); + } + + public function clearImportStatusFlag($flag) { + return $this->adjustImportStatusFlag($flag, false); + } + + private function adjustImportStatusFlag($flag, $set) { + $conn_w = $this->establishConnection('w'); + $table_name = $this->getTableName(); + $id = $this->getID(); + + if ($set) { + queryfx( + $conn_w, + 'UPDATE %T SET importStatus = (importStatus | %d) WHERE id = %d', + $table_name, + $flag, + $id); + + $this->setImportStatus($this->getImportStatus() | $flag); + } else { + queryfx( + $conn_w, + 'UPDATE %T SET importStatus = (importStatus & ~%d) WHERE id = %d', + $table_name, + $flag, + $id); + + $this->setImportStatus($this->getImportStatus() & ~$flag); + } + return $this; }