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

Prepare Diffusion for hovercards

Summary:
Move Diffusion to be hovercard-ready, and expand our ability to resolve commit references.

- Link unqualified hashes of 7 characters or more which match a commit.
- Link qualified hashes of 5 characters or more which match a commit.
- Support `{...}` syntax.

Test Plan: {F33896}

Reviewers: chad, vrana

Reviewed By: vrana

CC: aran

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

+283 -69
+5
resources/sql/patches/20130226.commitkey.sql
··· 1 + ALTER TABLE {$NAMESPACE}_repository.repository_commit 2 + DROP KEY `repositoryID`; 3 + 4 + ALTER TABLE {$NAMESPACE}_repository.repository_commit 5 + ADD UNIQUE KEY `key_commit_identity` (commitIdentifier, repositoryID);
+8 -4
src/__phutil_library_map__.php
··· 374 374 'DiffusionCommitController' => 'applications/diffusion/controller/DiffusionCommitController.php', 375 375 'DiffusionCommitEditController' => 'applications/diffusion/controller/DiffusionCommitEditController.php', 376 376 'DiffusionCommitParentsQuery' => 'applications/diffusion/query/parents/DiffusionCommitParentsQuery.php', 377 + 'DiffusionCommitQuery' => 'applications/diffusion/query/DiffusionCommitQuery.php', 377 378 'DiffusionCommitTagsController' => 'applications/diffusion/controller/DiffusionCommitTagsController.php', 378 379 'DiffusionCommitTagsQuery' => 'applications/diffusion/query/committags/DiffusionCommitTagsQuery.php', 379 380 'DiffusionContainsQuery' => 'applications/diffusion/query/contains/DiffusionContainsQuery.php', ··· 1186 1187 'PhabricatorRemarkupRuleMeme' => 'applications/macro/remarkup/PhabricatorRemarkupRuleMeme.php', 1187 1188 'PhabricatorRemarkupRuleMention' => 'applications/people/remarkup/PhabricatorRemarkupRuleMention.php', 1188 1189 'PhabricatorRemarkupRuleObject' => 'infrastructure/markup/rule/PhabricatorRemarkupRuleObject.php', 1189 - 'PhabricatorRemarkupRuleObjectName' => 'infrastructure/markup/rule/PhabricatorRemarkupRuleObjectName.php', 1190 1190 'PhabricatorRemarkupRuleYoutube' => 'infrastructure/markup/rule/PhabricatorRemarkupRuleYoutube.php', 1191 1191 'PhabricatorRepository' => 'applications/repository/storage/PhabricatorRepository.php', 1192 1192 'PhabricatorRepositoryArcanistProject' => 'applications/repository/storage/PhabricatorRepositoryArcanistProject.php', ··· 1898 1898 'DiffusionCommitController' => 'DiffusionController', 1899 1899 'DiffusionCommitEditController' => 'DiffusionController', 1900 1900 'DiffusionCommitParentsQuery' => 'DiffusionQuery', 1901 + 'DiffusionCommitQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 1901 1902 'DiffusionCommitTagsController' => 'DiffusionController', 1902 1903 'DiffusionCommitTagsQuery' => 'DiffusionQuery', 1903 1904 'DiffusionContainsQuery' => 'DiffusionQuery', ··· 1953 1954 'DiffusionPathValidateController' => 'DiffusionController', 1954 1955 'DiffusionPeopleMenuEventListener' => 'PhutilEventListener', 1955 1956 'DiffusionRawDiffQuery' => 'DiffusionQuery', 1956 - 'DiffusionRemarkupRule' => 'PhabricatorRemarkupRuleObjectName', 1957 + 'DiffusionRemarkupRule' => 'PhabricatorRemarkupRuleObject', 1957 1958 'DiffusionRepositoryController' => 'DiffusionController', 1958 1959 'DiffusionSetupException' => 'AphrontUsageException', 1959 1960 'DiffusionSvnBrowseQuery' => 'DiffusionBrowseQuery', ··· 2661 2662 'PhabricatorRemarkupRuleMeme' => 'PhutilRemarkupRule', 2662 2663 'PhabricatorRemarkupRuleMention' => 'PhutilRemarkupRule', 2663 2664 'PhabricatorRemarkupRuleObject' => 'PhutilRemarkupRule', 2664 - 'PhabricatorRemarkupRuleObjectName' => 'PhutilRemarkupRule', 2665 2665 'PhabricatorRemarkupRuleYoutube' => 'PhutilRemarkupRule', 2666 2666 'PhabricatorRepository' => 2667 2667 array( ··· 2673 2673 'PhabricatorRepositoryArcanistProjectEditController' => 'PhabricatorRepositoryController', 2674 2674 'PhabricatorRepositoryAuditRequest' => 'PhabricatorRepositoryDAO', 2675 2675 'PhabricatorRepositoryBranch' => 'PhabricatorRepositoryDAO', 2676 - 'PhabricatorRepositoryCommit' => 'PhabricatorRepositoryDAO', 2676 + 'PhabricatorRepositoryCommit' => 2677 + array( 2678 + 0 => 'PhabricatorRepositoryDAO', 2679 + 1 => 'PhabricatorPolicyInterface', 2680 + ), 2677 2681 'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker', 2678 2682 'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO', 2679 2683 'PhabricatorRepositoryCommitHeraldWorker' => 'PhabricatorRepositoryCommitParserWorker',
+6
src/applications/diffusion/application/PhabricatorApplicationDiffusion.php
··· 30 30 ); 31 31 } 32 32 33 + public function getRemarkupRules() { 34 + return array( 35 + new DiffusionRemarkupRule(), 36 + ); 37 + } 38 + 33 39 public function getRoutes() { 34 40 return array( 35 41 '/r(?P<callsign>[A-Z]+)(?P<commit>[a-z0-9]+)'
+140
src/applications/diffusion/query/DiffusionCommitQuery.php
··· 1 + <?php 2 + 3 + final class DiffusionCommitQuery 4 + extends PhabricatorCursorPagedPolicyAwareQuery { 5 + 6 + private $identifiers; 7 + 8 + /** 9 + * Load commits by partial or full identifiers, e.g. "rXab82393", "rX1234", 10 + * or "a9caf12". When an identifier matches multiple commits, they will all 11 + * be returned; callers should be prepared to deal with more results than 12 + * they queried for. 13 + */ 14 + public function withIdentifiers(array $identifiers) { 15 + $this->identifiers = $identifiers; 16 + return $this; 17 + } 18 + 19 + public function loadPage() { 20 + $table = new PhabricatorRepositoryCommit(); 21 + $conn_r = $table->establishConnection('r'); 22 + 23 + $data = queryfx_all( 24 + $conn_r, 25 + 'SELECT * FROM %T %Q %Q %Q', 26 + $table->getTableName(), 27 + $this->buildWhereClause($conn_r), 28 + $this->buildOrderClause($conn_r), 29 + $this->buildLimitClause($conn_r)); 30 + 31 + return $table->loadAllFromArray($data); 32 + } 33 + 34 + public function willFilterPage(array $commits) { 35 + if (!$commits) { 36 + return array(); 37 + } 38 + 39 + $repository_ids = mpull($commits, 'getRepositoryID', 'getRepositoryID'); 40 + $repos = id(new PhabricatorRepositoryQuery()) 41 + ->setViewer($this->getViewer()) 42 + ->withIDs($repository_ids) 43 + ->execute(); 44 + 45 + foreach ($commits as $key => $commit) { 46 + $repo = idx($repos, $commit->getRepositoryID()); 47 + if ($repo) { 48 + $commit->attachRepository($repo); 49 + } else { 50 + unset($commits[$key]); 51 + } 52 + } 53 + 54 + return $commits; 55 + } 56 + 57 + private function buildWhereClause(AphrontDatabaseConnection $conn_r) { 58 + $where = array(); 59 + 60 + if ($this->identifiers) { 61 + $min_unqualified = PhabricatorRepository::MINIMUM_UNQUALIFIED_HASH; 62 + $min_qualified = PhabricatorRepository::MINIMUM_QUALIFIED_HASH; 63 + 64 + $refs = array(); 65 + $bare = array(); 66 + foreach ($this->identifiers as $identifier) { 67 + $matches = null; 68 + preg_match('/^(?:r([A-Z]+))?(.*)$/', $identifier, $matches); 69 + $repo = nonempty($matches[1], null); 70 + $identifier = nonempty($matches[2], null); 71 + 72 + if ($repo === null) { 73 + if (strlen($identifier) < $min_unqualified) { 74 + continue; 75 + } 76 + $bare[] = $identifier; 77 + } else { 78 + $refs[] = array( 79 + 'callsign' => $repo, 80 + 'identifier' => $identifier, 81 + ); 82 + } 83 + } 84 + 85 + $sql = array(); 86 + 87 + foreach ($bare as $identifier) { 88 + $sql[] = qsprintf( 89 + $conn_r, 90 + '(commitIdentifier LIKE %> AND LENGTH(commitIdentifier) = 40)', 91 + $identifier); 92 + } 93 + 94 + if ($refs) { 95 + $callsigns = ipull($refs, 'callsign'); 96 + $repos = id(new PhabricatorRepositoryQuery()) 97 + ->setViewer($this->getViewer()) 98 + ->withCallsigns($callsigns) 99 + ->execute(); 100 + $repos = mpull($repos, null, 'getCallsign'); 101 + 102 + foreach ($refs as $key => $ref) { 103 + $repo = idx($repos, $ref['callsign']); 104 + if (!$repo) { 105 + continue; 106 + } 107 + 108 + if ($repo->isSVN()) { 109 + $sql[] = qsprintf( 110 + $conn_r, 111 + '(repositoryID = %d AND commitIdentifier = %d)', 112 + $repo->getID(), 113 + $ref['identifier']); 114 + } else { 115 + if (strlen($ref['identifier']) < $min_qualified) { 116 + continue; 117 + } 118 + $sql[] = qsprintf( 119 + $conn_r, 120 + '(repositoryID = %d AND commitIdentifier LIKE %>)', 121 + $repo->getID(), 122 + $ref['identifier']); 123 + } 124 + } 125 + } 126 + 127 + if ($sql) { 128 + $where[] = '('.implode(' OR ', $sql).')'; 129 + } else { 130 + // If we discarded all possible identifiers (e.g., they all referenced 131 + // bogus repositories or were all too short), make sure the query finds 132 + // nothing. 133 + $where[] = qsprintf($conn_r, '1 = 0'); 134 + } 135 + } 136 + 137 + return $this->formatWhereClause($where); 138 + } 139 + 140 + }
+68 -6
src/applications/diffusion/remarkup/DiffusionRemarkupRule.php
··· 1 1 <?php 2 2 3 - /** 4 - * @group markup 5 - */ 6 3 final class DiffusionRemarkupRule 7 - extends PhabricatorRemarkupRuleObjectName { 4 + extends PhabricatorRemarkupRuleObject { 8 5 9 6 protected function getObjectNamePrefix() { 10 - return 'r'; 7 + return ''; 11 8 } 12 9 13 10 protected function getObjectIDPattern() { 14 - return '[A-Z]+[a-f0-9]+'; 11 + $min_unqualified = PhabricatorRepository::MINIMUM_UNQUALIFIED_HASH; 12 + $min_qualified = PhabricatorRepository::MINIMUM_QUALIFIED_HASH; 13 + 14 + return 15 + '(?:r[A-Z]+)?[0-9]+'. 16 + '|'. 17 + '(?:r[A-Z]+)?[a-f0-9]{'.$min_qualified.',40}'. 18 + '|'. 19 + '[a-f0-9]{'.$min_unqualified.',40}'; 20 + } 21 + 22 + protected function loadObjects(array $ids) { 23 + $viewer = $this->getEngine()->getConfig('viewer'); 24 + $min_qualified = PhabricatorRepository::MINIMUM_QUALIFIED_HASH; 25 + 26 + if (!$viewer) { 27 + return array(); 28 + } 29 + 30 + $commits = id(new DiffusionCommitQuery()) 31 + ->setViewer($viewer) 32 + ->withIdentifiers($ids) 33 + ->execute(); 34 + 35 + if (!$commits) { 36 + return array(); 37 + } 38 + 39 + $ids = array_fuse($ids); 40 + 41 + $result = array(); 42 + foreach ($commits as $commit) { 43 + $prefix = 'r'.$commit->getRepository()->getCallsign(); 44 + $suffix = $commit->getCommitIdentifier(); 45 + 46 + if ($commit->getRepository()->isSVN()) { 47 + if (isset($ids[$prefix.$suffix])) { 48 + $result[$prefix.$suffix][] = $commit; 49 + } 50 + } else { 51 + // This awkward contruction is so we can link the commits up in O(N) 52 + // time instead of O(N^2). 53 + for ($ii = $min_qualified; $ii <= strlen($suffix); $ii++) { 54 + $part = substr($suffix, 0, $ii); 55 + if (isset($ids[$prefix.$part])) { 56 + $result[$prefix.$part][] = $commit; 57 + } 58 + if (isset($ids[$part])) { 59 + $result[$part][] = $commit; 60 + } 61 + } 62 + } 63 + } 64 + 65 + foreach ($result as $identifier => $commits) { 66 + if (count($commits) == 1) { 67 + $result[$identifier] = head($commits); 68 + } else { 69 + // This reference is ambiguous -- it matches more than one commit -- so 70 + // don't link it. We could potentially improve this, but it's a bit 71 + // tricky since the superclass expects a single object. 72 + unset($result[$identifier]); 73 + } 74 + } 75 + 76 + return $result; 15 77 } 16 78 17 79 }
+10
src/applications/repository/storage/PhabricatorRepository.php
··· 6 6 final class PhabricatorRepository extends PhabricatorRepositoryDAO 7 7 implements PhabricatorPolicyInterface { 8 8 9 + /** 10 + * Shortest hash we'll recognize in raw "a829f32" form. 11 + */ 12 + const MINIMUM_UNQUALIFIED_HASH = 7; 13 + 14 + /** 15 + * Shortest hash we'll recognize in qualified "rXab7ef2f8" form. 16 + */ 17 + const MINIMUM_QUALIFIED_HASH = 5; 18 + 9 19 const TABLE_PATH = 'repository_path'; 10 20 const TABLE_PATHCHANGE = 'repository_pathchange'; 11 21 const TABLE_FILESYSTEM = 'repository_filesystem';
+34 -1
src/applications/repository/storage/PhabricatorRepositoryCommit.php
··· 1 1 <?php 2 2 3 - final class PhabricatorRepositoryCommit extends PhabricatorRepositoryDAO { 3 + final class PhabricatorRepositoryCommit 4 + extends PhabricatorRepositoryDAO 5 + implements PhabricatorPolicyInterface { 4 6 5 7 protected $repositoryID; 6 8 protected $phid; ··· 14 16 private $commitData; 15 17 private $audits; 16 18 private $isUnparsed; 19 + private $repository; 20 + 21 + public function attachRepository(PhabricatorRepository $repository) { 22 + $this->repository = $repository; 23 + return $this; 24 + } 25 + 26 + public function getRepository() { 27 + if ($this->repository === null) { 28 + throw new Exception("Call attachRepository() before getRepository()!"); 29 + } 30 + return $this->repository; 31 + } 17 32 18 33 public function setIsUnparsed($is_unparsed) { 19 34 $this->isUnparsed = $is_unparsed; ··· 138 153 139 154 return $this->setAuditStatus($status); 140 155 } 156 + 157 + 158 + /* -( PhabricatorPolicyInterface )----------------------------------------- */ 159 + 160 + public function getCapabilities() { 161 + return array( 162 + PhabricatorPolicyCapability::CAN_VIEW, 163 + ); 164 + } 165 + 166 + public function getPolicy($capability) { 167 + return $this->getRepository()->getPolicy($capability); 168 + } 169 + 170 + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 171 + return $this->getRepository()->hasAutomaticCapability($capability, $viewer); 172 + } 173 + 141 174 }
+1 -4
src/infrastructure/markup/PhabricatorMarkupEngine.php
··· 41 41 42 42 private $objects = array(); 43 43 private $viewer; 44 - private $version = 4; 44 + private $version = 5; 45 45 46 46 47 47 /* -( Markup Pipeline )---------------------------------------------------- */ ··· 401 401 $rules[] = new PhrictionRemarkupRule(); 402 402 403 403 $rules[] = new PhabricatorRemarkupRuleEmbedFile(); 404 - 405 - $rules[] = new DiffusionRemarkupRule(); 406 - 407 404 $rules[] = new PhabricatorCountdownRemarkupRule(); 408 405 409 406 $applications = PhabricatorApplication::getAllInstalledApplications();
+7 -3
src/infrastructure/markup/rule/PhabricatorRemarkupRuleObject.php
··· 36 36 return $result; 37 37 } 38 38 39 - protected function renderObjectRef($object, $handle, $anchor) { 39 + protected function renderObjectRef($object, $handle, $anchor, $id) { 40 40 $href = $handle->getURI(); 41 - $text = $this->getObjectNamePrefix().$object->getID(); 41 + $text = $this->getObjectNamePrefix().$id; 42 42 if ($anchor) { 43 43 $matches = null; 44 44 if (preg_match('@^#(?:comment-)?(\d{1,7})$@', $anchor, $matches)) { ··· 172 172 $object = $objects[$spec['id']]; 173 173 switch ($spec['type']) { 174 174 case 'ref': 175 - $view = $this->renderObjectRef($object, $handle, $spec['anchor']); 175 + $view = $this->renderObjectRef( 176 + $object, 177 + $handle, 178 + $spec['anchor'], 179 + $spec['id']); 176 180 break; 177 181 case 'embed': 178 182 $view = $this->renderObjectEmbed($object, $handle, $spec['options']);
-51
src/infrastructure/markup/rule/PhabricatorRemarkupRuleObjectName.php
··· 1 - <?php 2 - 3 - /** 4 - * @group markup 5 - */ 6 - abstract class PhabricatorRemarkupRuleObjectName 7 - extends PhutilRemarkupRule { 8 - 9 - abstract protected function getObjectNamePrefix(); 10 - 11 - protected function getObjectIDPattern() { 12 - return '[1-9]\d*'; 13 - } 14 - 15 - public function apply($text) { 16 - $prefix = $this->getObjectNamePrefix(); 17 - $id = $this->getObjectIDPattern(); 18 - return preg_replace_callback( 19 - "@\b({$prefix})({$id})(?:#([-\w\d]+))?\b@", 20 - array($this, 'markupObjectNameLink'), 21 - $text); 22 - } 23 - 24 - public function markupObjectNameLink($matches) { 25 - list(, $prefix, $id) = $matches; 26 - 27 - if (isset($matches[3])) { 28 - $href = $matches[3]; 29 - $text = $matches[3]; 30 - if (preg_match('@^(?:comment-)?(\d{1,7})$@', $href, $matches)) { 31 - // Maximum length is 7 because 12345678 could be a file hash. 32 - $href = "comment-{$matches[1]}"; 33 - $text = $matches[1]; 34 - } 35 - $href = "/{$prefix}{$id}#{$href}"; 36 - $text = "{$prefix}{$id}#{$text}"; 37 - } else { 38 - $href = "/{$prefix}{$id}"; 39 - $text = "{$prefix}{$id}"; 40 - } 41 - 42 - return $this->getEngine()->storeText( 43 - phutil_tag( 44 - 'a', 45 - array( 46 - 'href' => $href, 47 - ), 48 - $text)); 49 - } 50 - 51 - }
+4
src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
··· 1153 1153 'type' => 'sql', 1154 1154 'name' => $this->getPatchPath('20130222.dropchannel.sql'), 1155 1155 ), 1156 + '20130226.commitkey.sql' => array( 1157 + 'type' => 'sql', 1158 + 'name' => $this->getPatchPath('20130226.commitkey.sql'), 1159 + ), 1156 1160 ); 1157 1161 } 1158 1162