1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-24 06:20:56 +01:00

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
This commit is contained in:
epriestley 2016-06-16 08:43:52 -07:00
parent 77ee518d88
commit 02d7bb8604
4 changed files with 148 additions and 12 deletions

View file

@ -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',

View file

@ -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");

View file

@ -0,0 +1,103 @@
<?php
final class PhabricatorRepositoryManagementMarkReachableWorkflow
extends PhabricatorRepositoryManagementWorkflow {
private $untouchedCount = 0;
protected function didConstruct() {
$this
->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);
}
}
}
}

View file

@ -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;
}