@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.

Make serving repositories work with alternate URIs

Summary: Ref T4245. Consolidates the URI parsing/rewriting logic so that repositories can be served from either `/diffusion/XYZ/` or `/diffusion/123/`, over both HTTP and SSH.

Test Plan:
- Pulled a Git repository by ID and callsign over HTTP and SSH.
- Pulled a Mercurial repository by ID and callsign over HTTP and SSH.
- Pulled a Subversion repository by ID and callsign over SSH (no HTTP support for SVN).

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T4245

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

+74 -22
+12 -4
src/applications/diffusion/controller/DiffusionServeController.php
··· 262 262 case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: 263 263 $result = new PhabricatorVCSResponse( 264 264 500, 265 - pht('This is not a Git repository.')); 265 + pht( 266 + 'This repository ("%s") is not a Git repository.', 267 + $repository->getDisplayName())); 266 268 break; 267 269 case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: 268 270 $result = new PhabricatorVCSResponse( 269 271 500, 270 - pht('This is not a Mercurial repository.')); 272 + pht( 273 + 'This repository ("%s") is not a Mercurial repository.', 274 + $repository->getDisplayName())); 271 275 break; 272 276 case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: 273 277 $result = new PhabricatorVCSResponse( 274 278 500, 275 - pht('This is not a Subversion repository.')); 279 + pht( 280 + 'This repository ("%s") is not a Subversion repository.', 281 + $repository->getDisplayName())); 276 282 break; 277 283 default: 278 284 $result = new PhabricatorVCSResponse( ··· 480 486 private function getRequestDirectoryPath(PhabricatorRepository $repository) { 481 487 $request = $this->getRequest(); 482 488 $request_path = $request->getRequestURI()->getPath(); 483 - $base_path = preg_replace('@^/diffusion/[A-Z]+@', '', $request_path); 489 + 490 + $info = PhabricatorRepository::parseRepositoryServicePath($request_path); 491 + $base_path = $info['path']; 484 492 485 493 // For Git repositories, strip an optional directory component if it 486 494 // isn't the name of a known Git resource. This allows users to clone
+21 -10
src/applications/diffusion/ssh/DiffusionSSHWorkflow.php
··· 6 6 private $repository; 7 7 private $hasWriteAccess; 8 8 private $proxyURI; 9 + private $baseRequestPath; 9 10 10 11 public function getRepository() { 11 12 if (!$this->repository) { ··· 44 45 */ 45 46 abstract protected function identifyRepository(); 46 47 abstract protected function executeRepositoryOperations(); 48 + 49 + protected function getBaseRequestPath() { 50 + return $this->baseRequestPath; 51 + } 47 52 48 53 protected function writeError($message) { 49 54 $this->getErrorChannel()->write($message); ··· 149 154 protected function loadRepositoryWithPath($path) { 150 155 $viewer = $this->getUser(); 151 156 152 - $regex = '@^/?diffusion/(?P<callsign>[A-Z]+)(?:/|\z)@'; 153 - $matches = null; 154 - if (!preg_match($regex, $path, $matches)) { 157 + $info = PhabricatorRepository::parseRepositoryServicePath($path); 158 + if ($info === null) { 155 159 throw new Exception( 156 160 pht( 157 - 'Unrecognized repository path "%s". Expected a path like "%s".', 161 + 'Unrecognized repository path "%s". Expected a path like "%s" '. 162 + 'or "%s".', 158 163 $path, 159 - '/diffusion/X/')); 164 + '/diffusion/X/', 165 + '/diffusion/123/')); 160 166 } 161 167 162 - $callsign = $matches[1]; 168 + $identifier = $info['identifier']; 169 + $base = $info['base']; 170 + 171 + $this->baseRequestPath = $base; 172 + 163 173 $repository = id(new PhabricatorRepositoryQuery()) 164 174 ->setViewer($viewer) 165 - ->withCallsigns(array($callsign)) 175 + ->withIdentifiers(array($identifier)) 166 176 ->executeOne(); 167 - 168 177 if (!$repository) { 169 178 throw new Exception( 170 - pht('No repository "%s" exists!', $callsign)); 179 + pht('No repository "%s" exists!', $identifier)); 171 180 } 172 181 173 182 switch ($repository->getServeOverSSH()) { ··· 179 188 case PhabricatorRepository::SERVE_OFF: 180 189 default: 181 190 throw new Exception( 182 - pht('This repository is not available over SSH.')); 191 + pht( 192 + 'This repository ("%s") is not available over SSH.', 193 + $repository->getDisplayName())); 183 194 } 184 195 185 196 return $repository;
+6 -8
src/applications/diffusion/ssh/DiffusionSubversionServeSSHWorkflow.php
··· 377 377 $repository = $this->getRepository(); 378 378 379 379 $path = $this->getPathFromSubversionURI($uri_string); 380 - $path = preg_replace( 381 - '(^/diffusion/[A-Z]+)', 382 - rtrim($repository->getLocalPath(), '/'), 383 - $path); 380 + $external_base = $this->getBaseRequestPath(); 384 381 385 - if (preg_match('(^/diffusion/[A-Z]+/\z)', $path)) { 386 - $path = rtrim($path, '/'); 387 - } 382 + // Replace "/diffusion/X" in the request with the repository local path, 383 + // so "/diffusion/X/master/" becomes "/path/to/repository/X/master/". 384 + $local_path = rtrim($repository->getLocalPath(), '/'); 385 + $path = $local_path.substr($path, strlen($external_base)); 388 386 389 387 // NOTE: We are intentionally NOT removing username information from the 390 388 // URI. Subversion retains it over the course of the request and considers ··· 398 396 if ($this->externalBaseURI === null) { 399 397 $pre = (string)id(clone $uri)->setPath(''); 400 398 401 - $external_path = '/diffusion/'.$repository->getCallsign(); 399 + $external_path = $external_base; 402 400 $external_path = $this->normalizeSVNPath($external_path); 403 401 $this->externalBaseURI = $pre.$external_path; 404 402
+35
src/applications/repository/storage/PhabricatorRepository.php
··· 687 687 return "/r{$callsign}{$identifier}"; 688 688 } 689 689 690 + public static function parseRepositoryServicePath($request_path) { 691 + // NOTE: In Mercurial over SSH, the path will begin without a leading "/", 692 + // so we're matching it optionally. 693 + 694 + $patterns = array( 695 + '(^'. 696 + '(?P<base>/?diffusion/(?P<identifier>[A-Z]+|[0-9]\d*))'. 697 + '(?P<path>(?:/.*)?)'. 698 + '\z)', 699 + ); 700 + 701 + $identifier = null; 702 + foreach ($patterns as $pattern) { 703 + $matches = null; 704 + if (!preg_match($pattern, $request_path, $matches)) { 705 + continue; 706 + } 707 + 708 + $identifier = $matches['identifier']; 709 + $base = $matches['base']; 710 + $path = $matches['path']; 711 + break; 712 + } 713 + 714 + if ($identifier === null) { 715 + return null; 716 + } 717 + 718 + return array( 719 + 'identifier' => $identifier, 720 + 'base' => $base, 721 + 'path' => $path, 722 + ); 723 + } 724 + 690 725 public function getCanonicalPath($request_path) { 691 726 $standard_pattern = 692 727 '(^'.