1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-18 11:30:55 +01:00

Support slightly prettier repository URIs in Diffusion

Summary: Fixes T4245. When a repository has a short name, use `/source/shortname/` as its primary URI.

Test Plan:
  - Cloned Git repositories from shortnames via HTTP and SSH.
  - Cloned Mercurial repositories from shortnames via HTTP and SSH.
  - Cloned Subversion repositories from shortnames via SSH.
  - Browsed Git, Mercurial and Subversion repositories.
  - Added and removed short names to various repositories.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T4245

Differential Revision: https://secure.phabricator.com/D16851
This commit is contained in:
epriestley 2016-11-13 11:49:50 -08:00
parent c9e140e283
commit 6a62fca950
11 changed files with 110 additions and 100 deletions

View file

@ -46,30 +46,9 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication {
} }
public function getRoutes() { public function getRoutes() {
return array( $repository_routes = array(
'/(?:'. '/' => array(
'r(?P<repositoryCallsign>[A-Z]+)'.
'|'.
'R(?P<repositoryID>[1-9]\d*):'.
')(?P<commit>[a-f0-9]+)'
=> 'DiffusionCommitController',
'/diffusion/' => array(
$this->getQueryRoutePattern()
=> 'DiffusionRepositoryListController',
$this->getEditRoutePattern('edit/') =>
'DiffusionRepositoryEditController',
'pushlog/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'DiffusionPushLogListController',
'view/(?P<id>\d+)/' => 'DiffusionPushEventViewController',
),
'(?:'.
'(?P<repositoryCallsign>[A-Z]+)'.
'|'.
'(?P<repositoryID>[1-9]\d*)'.
')/' => array(
'' => 'DiffusionRepositoryController', '' => 'DiffusionRepositoryController',
'repository/(?P<dblob>.*)' => 'DiffusionRepositoryController', 'repository/(?P<dblob>.*)' => 'DiffusionRepositoryController',
'change/(?P<dblob>.*)' => 'DiffusionChangeController', 'change/(?P<dblob>.*)' => 'DiffusionChangeController',
'history/(?P<dblob>.*)' => 'DiffusionHistoryController', 'history/(?P<dblob>.*)' => 'DiffusionHistoryController',
@ -107,13 +86,35 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication {
'pathtree/(?P<dblob>.*)' => 'DiffusionPathTreeController', 'pathtree/(?P<dblob>.*)' => 'DiffusionPathTreeController',
), ),
// NOTE: This must come after the rule above; it just gives us a // NOTE: This must come after the rules above; it just gives us a
// catch-all for serving repositories over HTTP. We must accept // catch-all for serving repositories over HTTP. We must accept requests
// requests without the trailing "/" because SVN commands don't // without the trailing "/" because SVN commands don't necessarily
// necessarily include it. // include it.
'(?:(?P<repositoryCallsign>[A-Z]+)|(?P<repositoryID>[1-9]\d*))'. '(?:/.*)?' => 'DiffusionRepositoryDefaultController',
'(?:/.*)?' );
=> 'DiffusionRepositoryDefaultController',
return array(
'/(?:'.
'r(?P<repositoryCallsign>[A-Z]+)'.
'|'.
'R(?P<repositoryID>[1-9]\d*):'.
')(?P<commit>[a-f0-9]+)'
=> 'DiffusionCommitController',
'/source/(?P<repositoryShortName>[^/.]+)(?P<dotgit>\.git)?'
=> $repository_routes,
'/diffusion/' => array(
$this->getQueryRoutePattern()
=> 'DiffusionRepositoryListController',
$this->getEditRoutePattern('edit/') =>
'DiffusionRepositoryEditController',
'pushlog/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'DiffusionPushLogListController',
'view/(?P<id>\d+)/' => 'DiffusionPushEventViewController',
),
'(?P<repositoryCallsign>[A-Z]+)' => $repository_routes,
'(?P<repositoryID>[1-9]\d*)' => $repository_routes,
'inline/' => array( 'inline/' => array(
'edit/(?P<phid>[^/]+)/' => 'DiffusionInlineCommentController', 'edit/(?P<phid>[^/]+)/' => 'DiffusionInlineCommentController',

View file

@ -90,6 +90,11 @@ abstract class DiffusionController extends PhabricatorController {
protected function getRepositoryIdentifierFromRequest( protected function getRepositoryIdentifierFromRequest(
AphrontRequest $request) { AphrontRequest $request) {
$short_name = $request->getURIData('repositoryShortName');
if (strlen($short_name)) {
return $short_name;
}
$identifier = $request->getURIData('repositoryCallsign'); $identifier = $request->getURIData('repositoryCallsign');
if (strlen($identifier)) { if (strlen($identifier)) {
return $identifier; return $identifier;

View file

@ -16,6 +16,7 @@ final class DiffusionLastModifiedController extends DiffusionController {
$drequest = $this->getDiffusionRequest(); $drequest = $this->getDiffusionRequest();
$paths = $request->getStr('paths'); $paths = $request->getStr('paths');
try { try {
$paths = phutil_json_decode($paths); $paths = phutil_json_decode($paths);
} catch (PhutilJSONParserException $ex) { } catch (PhutilJSONParserException $ex) {

View file

@ -88,6 +88,13 @@ final class DiffusionServeController extends DiffusionController {
} }
} }
// If the request was for a path like "/source/libphutil.git" but the
// repository is not a Git repository, reject the request.
$type_git = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
if ($request->getURIData('dotgit') && ($vcs !== $type_git)) {
return null;
}
return $vcs; return $vcs;
} }
@ -607,7 +614,9 @@ final class DiffusionServeController extends DiffusionController {
$request = $this->getRequest(); $request = $this->getRequest();
$request_path = $request->getRequestURI()->getPath(); $request_path = $request->getRequestURI()->getPath();
$info = PhabricatorRepository::parseRepositoryServicePath($request_path); $info = PhabricatorRepository::parseRepositoryServicePath(
$request_path,
$repository->getVersionControlSystem());
$base_path = $info['path']; $base_path = $info['path'];
// For Git repositories, strip an optional directory component if it // For Git repositories, strip an optional directory component if it

View file

@ -15,7 +15,9 @@ final class DiffusionGitLFSAuthenticateWorkflow
} }
protected function identifyRepository() { protected function identifyRepository() {
return $this->loadRepositoryWithPath($this->getLFSPathArgument()); return $this->loadRepositoryWithPath(
$this->getLFSPathArgument(),
PhabricatorRepositoryType::REPOSITORY_TYPE_GIT);
} }
private function getLFSPathArgument() { private function getLFSPathArgument() {

View file

@ -17,7 +17,9 @@ abstract class DiffusionGitSSHWorkflow
protected function identifyRepository() { protected function identifyRepository() {
$args = $this->getArgs(); $args = $this->getArgs();
$path = head($args->getArg('dir')); $path = head($args->getArg('dir'));
return $this->loadRepositoryWithPath($path); return $this->loadRepositoryWithPath(
$path,
PhabricatorRepositoryType::REPOSITORY_TYPE_GIT);
} }
protected function waitForGitClient() { protected function waitForGitClient() {

View file

@ -27,7 +27,9 @@ final class DiffusionMercurialServeSSHWorkflow
protected function identifyRepository() { protected function identifyRepository() {
$args = $this->getArgs(); $args = $this->getArgs();
$path = $args->getArg('repository'); $path = $args->getArg('repository');
return $this->loadRepositoryWithPath($path); return $this->loadRepositoryWithPath(
$path,
PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL);
} }
protected function executeRepositoryOperations() { protected function executeRepositoryOperations() {

View file

@ -161,18 +161,19 @@ abstract class DiffusionSSHWorkflow extends PhabricatorSSHWorkflow {
} }
} }
protected function loadRepositoryWithPath($path) { protected function loadRepositoryWithPath($path, $vcs) {
$viewer = $this->getUser(); $viewer = $this->getUser();
$info = PhabricatorRepository::parseRepositoryServicePath($path); $info = PhabricatorRepository::parseRepositoryServicePath($path, $vcs);
if ($info === null) { if ($info === null) {
throw new Exception( throw new Exception(
pht( pht(
'Unrecognized repository path "%s". Expected a path like "%s" '. 'Unrecognized repository path "%s". Expected a path like "%s", '.
'or "%s".', '"%s", or "%s".',
$path, $path,
'/diffusion/X/', '/diffusion/X/',
'/diffusion/123/')); '/diffusion/123/',
'/source/thaumaturgy.git'));
} }
$identifier = $info['identifier']; $identifier = $info['identifier'];

View file

@ -117,7 +117,9 @@ final class DiffusionSubversionServeSSHWorkflow
$uri = $struct[2]['value']; $uri = $struct[2]['value'];
$path = $this->getPathFromSubversionURI($uri); $path = $this->getPathFromSubversionURI($uri);
return $this->loadRepositoryWithPath($path); return $this->loadRepositoryWithPath(
$path,
PhabricatorRepositoryType::REPOSITORY_TYPE_SVN);
} }
} }

View file

@ -563,6 +563,11 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
} }
public function getURI() { public function getURI() {
$short_name = $this->getRepositorySlug();
if (strlen($short_name)) {
return "/source/{$short_name}/";
}
$callsign = $this->getCallsign(); $callsign = $this->getCallsign();
if (strlen($callsign)) { if (strlen($callsign)) {
return "/diffusion/{$callsign}/"; return "/diffusion/{$callsign}/";
@ -573,7 +578,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
} }
public function getPathURI($path) { public function getPathURI($path) {
return $this->getURI().$path; return $this->getURI().ltrim($path, '/');
} }
public function getCommitURI($identifier) { public function getCommitURI($identifier) {
@ -586,14 +591,22 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
return "/R{$id}:{$identifier}"; return "/R{$id}:{$identifier}";
} }
public static function parseRepositoryServicePath($request_path) { public static function parseRepositoryServicePath($request_path, $vcs) {
// NOTE: In Mercurial over SSH, the path will begin without a leading "/", // NOTE: In Mercurial over SSH, the path will begin without a leading "/",
// so we're matching it optionally. // so we're matching it optionally.
if ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_GIT) {
$maybe_git = '(?:\\.git)?';
} else {
$maybe_git = null;
}
$patterns = array( $patterns = array(
'(^'. '(^'.
'(?P<base>/?diffusion/(?P<identifier>[A-Z]+|[0-9]\d*))'. '(?P<base>/?(?:diffusion|source)/(?P<identifier>[^/.]+))'.
'(?P<path>(?:/.*)?)'. $maybe_git.
'(?P<path>(?:/|.*)?)'.
'\z)', '\z)',
); );
@ -624,28 +637,15 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
public function getCanonicalPath($request_path) { public function getCanonicalPath($request_path) {
$standard_pattern = $standard_pattern =
'(^'. '(^'.
'(?P<prefix>/diffusion/)'. '(?P<prefix>/(?:diffusion|source)/)'.
'(?P<identifier>[^/]+)'. '(?P<identifier>[^/]+)'.
'(?P<suffix>(?:/.*)?)'. '(?P<suffix>(?:/.*)?)'.
'\z)'; '\z)';
$matches = null; $matches = null;
if (preg_match($standard_pattern, $request_path, $matches)) { if (preg_match($standard_pattern, $request_path, $matches)) {
$prefix = $matches['prefix'];
$callsign = $this->getCallsign();
if ($callsign) {
$identifier = $callsign;
} else {
$identifier = $this->getID();
}
$suffix = $matches['suffix']; $suffix = $matches['suffix'];
if (!strlen($suffix)) { return $this->getPathURI($suffix);
$suffix = '/';
}
return $prefix.$identifier.$suffix;
} }
$commit_pattern = $commit_pattern =
@ -724,18 +724,6 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
return $this->getCommitURI($commit); return $this->getCommitURI($commit);
} }
$identifier = $this->getID();
$callsign = $this->getCallsign();
if ($callsign !== null) {
$identifier = $callsign;
}
if (strlen($identifier)) {
$identifier = phutil_escape_uri_path_component($identifier);
}
if (strlen($path)) { if (strlen($path)) {
$path = ltrim($path, '/'); $path = ltrim($path, '/');
$path = str_replace(array(';', '$'), array(';;', '$$'), $path); $path = str_replace(array(';', '$'), array(';;', '$$'), $path);
@ -766,13 +754,13 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
case 'lint': case 'lint':
case 'pathtree': case 'pathtree':
case 'refs': case 'refs':
$uri = "/diffusion/{$identifier}/{$action}/{$path}{$commit}{$line}"; $uri = $this->getPathURI("/{$action}/{$path}{$commit}{$line}");
break; break;
case 'branch': case 'branch':
if (strlen($path)) { if (strlen($path)) {
$uri = "/diffusion/{$identifier}/repository/{$path}"; $uri = $this->getPathURI("/repository/{$path}");
} else { } else {
$uri = "/diffusion/{$identifier}/"; $uri = $this->getPathURI();
} }
break; break;
case 'external': case 'external':
@ -2108,9 +2096,6 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
$has_callsign = ($this->getCallsign() !== null); $has_callsign = ($this->getCallsign() !== null);
$has_shortname = ($this->getRepositorySlug() !== null); $has_shortname = ($this->getRepositorySlug() !== null);
// TODO: For now, never enable these because they don't work yet.
$has_shortname = false;
$identifier_map = array( $identifier_map = array(
PhabricatorRepositoryURI::BUILTIN_IDENTIFIER_CALLSIGN => $has_callsign, PhabricatorRepositoryURI::BUILTIN_IDENTIFIER_CALLSIGN => $has_callsign,
PhabricatorRepositoryURI::BUILTIN_IDENTIFIER_SHORTNAME => $has_shortname, PhabricatorRepositoryURI::BUILTIN_IDENTIFIER_SHORTNAME => $has_shortname,

View file

@ -125,8 +125,8 @@ final class PhabricatorRepositoryURI
$other_uris = $repository->getURIs(); $other_uris = $repository->getURIs();
$identifier_value = array( $identifier_value = array(
self::BUILTIN_IDENTIFIER_CALLSIGN => 3, self::BUILTIN_IDENTIFIER_SHORTNAME => 3,
self::BUILTIN_IDENTIFIER_SHORTNAME => 2, self::BUILTIN_IDENTIFIER_CALLSIGN => 2,
self::BUILTIN_IDENTIFIER_ID => 1, self::BUILTIN_IDENTIFIER_ID => 1,
); );