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);
         }
     }
 }
 private function pushRepositoryToMirror(PhabricatorRepository $repository, PhabricatorRepositoryURI $mirror_uri)
 {
     $this->log(pht('Pushing to remote "%s"...', $mirror_uri->getEffectiveURI()));
     if ($repository->isGit()) {
         $this->pushToGitRepository($repository, $mirror_uri);
     } else {
         if ($repository->isHg()) {
             $this->pushToHgRepository($repository, $mirror_uri);
         } else {
             throw new Exception(pht('Unsupported VCS!'));
         }
     }
 }
 private function getRequestDirectoryPath(PhabricatorRepository $repository)
 {
     $request = $this->getRequest();
     $request_path = $request->getRequestURI()->getPath();
     $base_path = preg_replace('@^/diffusion/[A-Z]+@', '', $request_path);
     // For Git repositories, strip an optional directory component if it
     // isn't the name of a known Git resource. This allows users to clone
     // repositories as "/diffusion/X/anything.git", for example.
     if ($repository->isGit()) {
         $known = array('info', 'git-upload-pack', 'git-receive-pack');
         foreach ($known as $key => $path) {
             $known[$key] = preg_quote($path, '@');
         }
         $known = implode('|', $known);
         if (preg_match('@^/([^/]+)/(' . $known . ')(/|$)@', $base_path)) {
             $base_path = preg_replace('@^/([^/]+)@', '', $base_path);
         }
     }
     return $base_path;
 }
 private function markUnreachableCommits(PhabricatorRepository $repository)
 {
     // For now, this is only supported for Git.
     if (!$repository->isGit()) {
         return;
     }
     // Find older versions of refs which we haven't processed yet. We're going
     // to make sure their commits are still reachable.
     $old_refs = id(new PhabricatorRepositoryOldRef())->loadAllWhere('repositoryPHID = %s', $repository->getPHID());
     // We can share a single graph stream across all the checks we need to do.
     $stream = new PhabricatorGitGraphStream($repository);
     foreach ($old_refs as $old_ref) {
         $identifier = $old_ref->getCommitIdentifier();
         $this->markUnreachableFrom($repository, $stream, $identifier);
         // If nothing threw an exception, we're all done with this ref.
         $old_ref->delete();
     }
 }
 private function rebuildRepository(PhabricatorRepository $repo)
 {
     $console = PhutilConsole::getConsole();
     $console->writeOut("%s\n", pht('Rebuilding "%s"...', $repo->getMonogram()));
     $refs = id(new PhabricatorRepositoryRefCursorQuery())->setViewer($this->getViewer())->withRefTypes(array(PhabricatorRepositoryRefCursor::TYPE_BRANCH))->withRepositoryPHIDs(array($repo->getPHID()))->execute();
     $graph = array();
     foreach ($refs as $ref) {
         if (!$repo->shouldTrackBranch($ref->getRefName())) {
             continue;
         }
         $console->writeOut("%s\n", pht('Rebuilding branch "%s"...', $ref->getRefName()));
         $commit = $ref->getCommitIdentifier();
         if ($repo->isGit()) {
             $stream = new PhabricatorGitGraphStream($repo, $commit);
         } else {
             $stream = new PhabricatorMercurialGraphStream($repo, $commit);
         }
         $discover = array($commit);
         while ($discover) {
             $target = array_pop($discover);
             if (isset($graph[$target])) {
                 continue;
             }
             $graph[$target] = $stream->getParents($target);
             foreach ($graph[$target] as $parent) {
                 $discover[] = $parent;
             }
         }
     }
     $console->writeOut("%s\n", pht('Found %s total commit(s); updating...', phutil_count($graph)));
     $commit_table = id(new PhabricatorRepositoryCommit());
     $commit_table_name = $commit_table->getTableName();
     $conn_w = $commit_table->establishConnection('w');
     $bar = id(new PhutilConsoleProgressBar())->setTotal(count($graph));
     $need = array();
     foreach ($graph as $child => $parents) {
         foreach ($parents as $parent) {
             $need[$parent] = $parent;
         }
         $need[$child] = $child;
     }
     $map = array();
     foreach (array_chunk($need, 2048) as $chunk) {
         $rows = queryfx_all($conn_w, 'SELECT id, commitIdentifier FROM %T
       WHERE commitIdentifier IN (%Ls) AND repositoryID = %d', $commit_table_name, $chunk, $repo->getID());
         foreach ($rows as $row) {
             $map[$row['commitIdentifier']] = $row['id'];
         }
     }
     $insert_sql = array();
     $delete_sql = array();
     foreach ($graph as $child => $parents) {
         $names = $parents;
         $names[] = $child;
         foreach ($names as $name) {
             if (empty($map[$name])) {
                 throw new Exception(pht('Unknown commit "%s"!', $name));
             }
         }
         if (!$parents) {
             // Write an explicit 0 to indicate "no parents" instead of "no data".
             $insert_sql[] = qsprintf($conn_w, '(%d, 0)', $map[$child]);
         } else {
             foreach ($parents as $parent) {
                 $insert_sql[] = qsprintf($conn_w, '(%d, %d)', $map[$child], $map[$parent]);
             }
         }
         $delete_sql[] = $map[$child];
         $bar->update(1);
     }
     $commit_table->openTransaction();
     foreach (PhabricatorLiskDAO::chunkSQL($delete_sql) as $chunk) {
         queryfx($conn_w, 'DELETE FROM %T WHERE childCommitID IN (%Q)', PhabricatorRepository::TABLE_PARENTS, $chunk);
     }
     foreach (PhabricatorLiskDAO::chunkSQL($insert_sql) as $chunk) {
         queryfx($conn_w, 'INSERT INTO %T (childCommitID, parentCommitID) VALUES %Q', PhabricatorRepository::TABLE_PARENTS, $chunk);
     }
     $commit_table->saveTransaction();
     $bar->done();
 }
 public function shouldEnableForRepository(PhabricatorRepository $repository)
 {
     return $repository->isGit();
 }
 protected function canBuildForRepository(PhabricatorRepository $repository)
 {
     return $repository->isGit();
 }
 private function getObservedVersion(PhabricatorRepository $repository)
 {
     if ($repository->isHosted()) {
         return null;
     }
     if ($repository->isGit()) {
         return $this->getGitObservedVersion($repository);
     }
     return null;
 }
 private function markUnreachableCommits(PhabricatorRepository $repository)
 {
     // For now, this is only supported for Git.
     if (!$repository->isGit()) {
         return;
     }
     // Find older versions of refs which we haven't processed yet. We're going
     // to make sure their commits are still reachable.
     $old_refs = id(new PhabricatorRepositoryOldRef())->loadAllWhere('repositoryPHID = %s', $repository->getPHID());
     // If we don't have any refs to update, bail out before building a graph
     // stream. In particular, this improves behavior in empty repositories,
     // where `git log` exits with an error.
     if (!$old_refs) {
         return;
     }
     // We can share a single graph stream across all the checks we need to do.
     $stream = new PhabricatorGitGraphStream($repository);
     foreach ($old_refs as $old_ref) {
         $identifier = $old_ref->getCommitIdentifier();
         $this->markUnreachableFrom($repository, $stream, $identifier);
         // If nothing threw an exception, we're all done with this ref.
         $old_ref->delete();
     }
 }