@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

Make Subversion URI construction more consistent

Summary:
Ref T2230. SVN has some weird rules about path construction. Particularly, if you're missing a "/" in the remote URI right now, the change parsing step doesn't build the right paths.

Instead, build the right paths more intelligently.

Test Plan: Added and executed unit tests. Imported an SVN repo.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran, jpeffer

Maniphest Tasks: T2230

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

+75 -21
+23 -4
src/applications/repository/storage/PhabricatorRepository.php
··· 156 156 } 157 157 158 158 public function getSubversionBaseURI() { 159 + $subpath = $this->getDetail('svn-subpath'); 160 + if (!strlen($subpath)) { 161 + $subpath = null; 162 + } 163 + return $this->getSubversionPathURI($subpath); 164 + } 165 + 166 + public function getSubversionPathURI($path = null, $commit = null) { 159 167 $vcs = $this->getVersionControlSystem(); 160 168 if ($vcs != PhabricatorRepositoryType::REPOSITORY_TYPE_SVN) { 161 169 throw new Exception("Not a subversion repository!"); ··· 167 175 $uri = $this->getDetail('remote-uri'); 168 176 } 169 177 170 - $subpath = $this->getDetail('svn-subpath'); 171 - if ($subpath) { 172 - $subpath = '/'.ltrim($subpath, '/'); 178 + $uri = rtrim($uri, '/'); 179 + 180 + if (strlen($path)) { 181 + $path = rawurlencode($path); 182 + $path = str_replace('%2F', '/', $path); 183 + $uri = $uri.'/'.ltrim($path, '/'); 184 + } 185 + 186 + if ($path !== null || $commit !== null) { 187 + $uri .= '@'; 188 + } 189 + 190 + if ($commit !== null) { 191 + $uri .= $commit; 173 192 } 174 193 175 - return $uri.$subpath; 194 + return $uri; 176 195 } 177 196 178 197 public function execRemoteCommand($pattern /* , $arg, ... */) {
+42
src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php
··· 55 55 'Do not track unlisted branches.'); 56 56 } 57 57 58 + public function testSubversionPathInfo() { 59 + $svn = PhabricatorRepositoryType::REPOSITORY_TYPE_SVN; 60 + 61 + $repo = new PhabricatorRepository(); 62 + $repo->setVersionControlSystem($svn); 63 + 64 + $repo->setDetail('remote-uri', 'http://svn.example.com/repo'); 65 + $this->assertEqual( 66 + 'http://svn.example.com/repo', 67 + $repo->getSubversionPathURI()); 68 + 69 + $repo->setDetail('remote-uri', 'http://svn.example.com/repo/'); 70 + $this->assertEqual( 71 + 'http://svn.example.com/repo', 72 + $repo->getSubversionPathURI()); 73 + 74 + $repo->setDetail('hosting-enabled', true); 75 + 76 + $repo->setDetail('local-path', '/var/repo/SVN'); 77 + $this->assertEqual( 78 + 'file:///var/repo/SVN', 79 + $repo->getSubversionPathURI()); 80 + 81 + $repo->setDetail('local-path', '/var/repo/SVN/'); 82 + $this->assertEqual( 83 + 'file:///var/repo/SVN', 84 + $repo->getSubversionPathURI()); 85 + 86 + $this->assertEqual( 87 + 'file:///var/repo/SVN/a@', 88 + $repo->getSubversionPathURI('a')); 89 + 90 + $this->assertEqual( 91 + 'file:///var/repo/SVN/a@1', 92 + $repo->getSubversionPathURI('a', 1)); 93 + 94 + $this->assertEqual( 95 + 'file:///var/repo/SVN/%3F@22', 96 + $repo->getSubversionPathURI('?', 22)); 97 + } 98 + 99 + 58 100 }
+10 -17
src/applications/repository/worker/commitchangeparser/PhabricatorRepositorySvnCommitChangeParserWorker.php
··· 24 24 // recursive paths were affected if it was moved or copied. This is very 25 25 // complicated and has many special cases. 26 26 27 - $uri = $repository->getDetail('remote-uri'); 27 + $uri = $repository->getSubversionPathURI(); 28 28 $svn_commit = $commit->getCommitIdentifier(); 29 29 30 30 // Pull the top-level path changes out of "svn log". This is pretty ··· 561 561 array $paths) { 562 562 563 563 $result_map = array(); 564 - $repository_uri = $repository->getDetail('remote-uri'); 564 + $repository_uri = $repository->getSubversionPathURI(); 565 565 566 566 if (isset($paths['/'])) { 567 567 $result_map['/'] = DifferentialChangeType::FILE_DIRECTORY; ··· 572 572 $path_mapping = array(); 573 573 foreach ($paths as $path => $lookup) { 574 574 $parent = dirname($lookup['rawPath']); 575 - $parent = ltrim($parent, '/'); 576 - $parent = $this->encodeSVNPath($parent); 577 - $parent = $repository_uri.$parent.'@'.$lookup['rawCommit']; 575 + $parent = $repository->getSubversionPathURI( 576 + $parent, 577 + $lookup['rawCommit']); 578 + 578 579 $parent = escapeshellarg($parent); 579 580 $parents[$parent] = true; 580 581 $path_mapping[$parent][] = dirname($path); ··· 626 627 return $result_map; 627 628 } 628 629 629 - private function encodeSVNPath($path) { 630 - $path = rawurlencode($path); 631 - $path = str_replace('%2F', '/', $path); 632 - return $path; 633 - } 634 - 635 630 private function getFileTypeFromSVNKind($kind) { 636 631 $kind = (string)$kind; 637 632 switch ($kind) { ··· 648 643 649 644 $path = $info['rawPath']; 650 645 $rev = $info['rawCommit']; 651 - $path = $this->encodeSVNPath($path); 652 646 653 - $hashkey = md5($repository->getDetail('remote-uri').$path.'@'.$rev); 647 + $path_uri = $repository->getSubversionPathURI($path, $rev); 648 + $hashkey = md5($path_uri); 654 649 655 650 // This method is quite horrible. The underlying challenge is that some 656 651 // commits in the Facebook repository are enormous, taking multiple hours ··· 664 659 if (!Filesystem::pathExists($cache_loc)) { 665 660 $tmp = new TempFile(); 666 661 $repository->execxRemoteCommand( 667 - '--xml ls -R %s%s@%d > %s', 668 - $repository->getDetail('remote-uri'), 669 - $path, 670 - $rev, 662 + '--xml ls -R %s > %s', 663 + $path_uri, 671 664 $tmp); 672 665 execx( 673 666 'mv %s %s',