@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Move Mercurial discovery to PhabricatorRepositoryDiscoveryEngine

Summary: Ref T4068. Partly, this moves discovery to the more unit-testable PhabricatorRepositoryDiscoveryEngine. It also fixes some issues, see inlines.

Test Plan: In a Mercurial repository, ran `bin/repository discover --repair`, verified commits came out topographically sorted. Ran without `--repair` and in various other contexts, like with no commits to discover and some-but-not-all commits to discover.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T4068

Differential Revision: https://secure.phabricator.com/D7518

+110 -69
+1 -62
src/applications/repository/daemon/PhabricatorRepositoryPullLocalDaemon.php
··· 232 232 $result = $this->executeGitDiscover($repository); 233 233 break; 234 234 case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: 235 + case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: 235 236 $refs = $this->getDiscoveryEngine($repository) 236 237 ->discoverCommits(); 237 - break; 238 - case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: 239 - $result = $this->executeHgDiscover($repository); 240 238 break; 241 239 default: 242 240 throw new Exception("Unknown VCS '{$vcs}'!"); ··· 738 736 return $path; 739 737 } 740 738 741 - 742 - /* -( Mercurial Implementation )------------------------------------------- */ 743 - 744 - 745 - private function executeHgDiscover(PhabricatorRepository $repository) { 746 - 747 - $branches = id(new DiffusionLowLevelMercurialBranchesQuery()) 748 - ->setRepository($repository) 749 - ->execute(); 750 - $branches = mpull($branches, 'getHeadCommitIdentifier', 'getName'); 751 - 752 - $got_something = false; 753 - foreach ($branches as $name => $commit) { 754 - if ($this->isKnownCommit($repository, $commit)) { 755 - continue; 756 - } else { 757 - $this->executeHgDiscoverCommit($repository, $commit); 758 - $got_something = true; 759 - } 760 - } 761 - 762 - return $got_something; 763 - } 764 - 765 - private function executeHgDiscoverCommit( 766 - PhabricatorRepository $repository, 767 - $commit) { 768 - 769 - $discover = array($commit); 770 - $insert = array($commit); 771 - 772 - $seen_parent = array(); 773 - 774 - $stream = new PhabricatorMercurialGraphStream($repository); 775 - 776 - // For all the new commits at the branch heads, walk backward until we 777 - // find only commits we've aleady seen. 778 - while ($discover) { 779 - $target = array_pop($discover); 780 - 781 - $parents = $stream->getParents($target); 782 - 783 - foreach ($parents as $parent) { 784 - if (isset($seen_parent[$parent])) { 785 - continue; 786 - } 787 - $seen_parent[$parent] = true; 788 - if (!$this->isKnownCommit($repository, $parent)) { 789 - $discover[] = $parent; 790 - $insert[] = $parent; 791 - } 792 - } 793 - } 794 - 795 - foreach ($insert as $target) { 796 - $epoch = $stream->getCommitDate($target); 797 - $this->recordCommit($repository, $target, $epoch); 798 - } 799 - } 800 739 801 740 }
+109 -7
src/applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php
··· 40 40 case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: 41 41 $refs = $this->discoverSubversionCommits(); 42 42 break; 43 + case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: 44 + $refs = $this->discoverMercurialCommits(); 45 + break; 43 46 /* 44 - 45 - TODO: Implement these! 47 + TODO: Implement this! 46 48 47 49 case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: 48 - $refs = $this->executeGitDiscovery(); 49 - break; 50 - case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: 51 - $refs = $this->executeMercurialDiscovery(); 50 + $refs = $this->discoverGitCommits(); 52 51 break; 53 - 54 52 */ 55 53 default: 56 54 throw new Exception("Unknown VCS '{$vcs}'!"); ··· 138 136 } 139 137 140 138 139 + /* -( Discovering Mercurial Repositories )--------------------------------- */ 140 + 141 + 142 + /** 143 + * @task hg 144 + */ 145 + private function discoverMercurialCommits() { 146 + $repository = $this->getRepository(); 147 + 148 + $branches = id(new DiffusionLowLevelMercurialBranchesQuery()) 149 + ->setRepository($repository) 150 + ->execute(); 151 + $branches = mpull($branches, 'getHeadCommitIdentifier', 'getName'); 152 + 153 + $refs = array(); 154 + foreach ($branches as $name => $commit) { 155 + $this->log("Examining branch '{$name}', at {$commit}'."); 156 + if (!$repository->shouldTrackBranch($name)) { 157 + $this->log("Skipping, branch is untracked."); 158 + continue; 159 + } 160 + 161 + if ($this->isKnownCommit($commit)) { 162 + $this->log("Skipping, tip is a known commit."); 163 + continue; 164 + } 165 + 166 + $this->log("Looking for new commits."); 167 + $refs[] = $this->discoverMercurialAncestry($repository, $commit); 168 + } 169 + 170 + return array_mergev($refs); 171 + } 172 + 173 + 174 + /** 175 + * @task hg 176 + */ 177 + private function discoverMercurialAncestry( 178 + PhabricatorRepository $repository, 179 + $commit) { 180 + 181 + $discover = array($commit); 182 + $graph = array(); 183 + $seen = array(); 184 + 185 + $stream = new PhabricatorMercurialGraphStream($repository); 186 + 187 + // Find all the reachable, undiscovered commits. Build a graph of the 188 + // edges. 189 + while ($discover) { 190 + $target = array_pop($discover); 191 + 192 + if (empty($graph[$target])) { 193 + $graph[$target] = array(); 194 + } 195 + 196 + $parents = $stream->getParents($target); 197 + foreach ($parents as $parent) { 198 + if ($this->isKnownCommit($parent)) { 199 + continue; 200 + } 201 + 202 + $graph[$target][$parent] = true; 203 + 204 + if (empty($seen[$parent])) { 205 + $seen[$parent] = true; 206 + $discover[] = $parent; 207 + } 208 + } 209 + } 210 + 211 + // Now, sort them topographically. 212 + $commits = $this->reduceGraph($graph); 213 + 214 + $refs = array(); 215 + foreach ($commits as $commit) { 216 + $refs[] = id(new PhabricatorRepositoryCommitRef()) 217 + ->setIdentifier($commit) 218 + ->setEpoch($stream->getCommitDate($commit)); 219 + } 220 + 221 + return $refs; 222 + } 223 + 224 + 141 225 /* -( Internals )---------------------------------------------------------- */ 226 + 227 + 228 + private function reduceGraph(array $edges) { 229 + foreach ($edges as $commit => $parents) { 230 + $edges[$commit] = array_keys($parents); 231 + } 232 + 233 + $graph = new PhutilDirectedScalarGraph(); 234 + $graph->addNodes($edges); 235 + 236 + $commits = $graph->getTopographicallySortedNodes(); 237 + 238 + // NOTE: We want the most ancestral nodes first, so we need to reverse the 239 + // list we get out of AbstractDirectedGraph. 240 + $commits = array_reverse($commits); 241 + 242 + return $commits; 243 + } 142 244 143 245 144 246 private function isKnownCommit($identifier) {