[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 <?php 2 3 final class DiffusionHistoryQueryConduitAPIMethod 4 extends DiffusionQueryConduitAPIMethod { 5 6 private $parents = array(); 7 8 public function getAPIMethodName() { 9 return 'diffusion.historyquery'; 10 } 11 12 public function getMethodDescription() { 13 return 'Returns history information for a repository at a specific '. 14 'commit and path.'; 15 } 16 17 public function defineReturnType() { 18 return 'array'; 19 } 20 21 protected function defineCustomParamTypes() { 22 return array( 23 'commit' => 'required string', 24 'path' => 'required string', 25 'offset' => 'required int', 26 'limit' => 'required int', 27 'needDirectChanges' => 'optional bool', 28 'needChildChanges' => 'optional bool', 29 ); 30 } 31 32 protected function getResult(ConduitAPIRequest $request) { 33 $path_changes = parent::getResult($request); 34 35 return array( 36 'pathChanges' => mpull($path_changes, 'toDictionary'), 37 'parents' => $this->parents, 38 ); 39 } 40 41 protected function getGitResult(ConduitAPIRequest $request) { 42 $drequest = $this->getDiffusionRequest(); 43 $repository = $drequest->getRepository(); 44 $commit_hash = $request->getValue('commit'); 45 $path = $request->getValue('path'); 46 $offset = $request->getValue('offset'); 47 $limit = $request->getValue('limit'); 48 49 list($stdout) = $repository->execxLocalCommand( 50 'log '. 51 '--skip=%d '. 52 '-n %d '. 53 '--pretty=format:%s '. 54 '%s -- %C', 55 $offset, 56 $limit, 57 '%H:%P', 58 $commit_hash, 59 // Git omits merge commits if the path is provided, even if it is empty. 60 (strlen($path) ? csprintf('%s', $path) : '')); 61 62 $lines = explode("\n", trim($stdout)); 63 $lines = array_filter($lines); 64 if (!$lines) { 65 return array(); 66 } 67 68 $hash_list = array(); 69 $parent_map = array(); 70 foreach ($lines as $line) { 71 list($hash, $parents) = explode(':', $line); 72 $hash_list[] = $hash; 73 $parent_map[$hash] = preg_split('/\s+/', $parents); 74 } 75 76 $this->parents = $parent_map; 77 78 return DiffusionQuery::loadHistoryForCommitIdentifiers( 79 $hash_list, 80 $drequest); 81 } 82 83 protected function getMercurialResult(ConduitAPIRequest $request) { 84 $drequest = $this->getDiffusionRequest(); 85 $repository = $drequest->getRepository(); 86 $commit_hash = $request->getValue('commit'); 87 $path = $request->getValue('path'); 88 $offset = $request->getValue('offset'); 89 $limit = $request->getValue('limit'); 90 91 $path = DiffusionPathIDQuery::normalizePath($path); 92 $path = ltrim($path, '/'); 93 94 // NOTE: Older versions of Mercurial give different results for these 95 // commands (see T1268): 96 // 97 // $ hg log -- '' 98 // $ hg log 99 // 100 // All versions of Mercurial give different results for these commands 101 // (merge commits are excluded with the "." version): 102 // 103 // $ hg log -- . 104 // $ hg log 105 // 106 // If we don't have a path component in the query, omit it from the command 107 // entirely to avoid these inconsistencies. 108 109 // NOTE: When viewing the history of a file, we don't use "-b", because 110 // Mercurial stops history at the branchpoint but we're interested in all 111 // ancestors. When viewing history of a branch, we do use "-b", and thus 112 // stop history (this is more consistent with the Mercurial worldview of 113 // branches). 114 115 if (strlen($path)) { 116 $path_arg = csprintf('-- %s', $path); 117 $branch_arg = ''; 118 } else { 119 $path_arg = ''; 120 // NOTE: --branch used to be called --only-branch; use -b for 121 // compatibility. 122 $branch_arg = csprintf('-b %s', $drequest->getBranch()); 123 } 124 125 list($stdout) = $repository->execxLocalCommand( 126 'log --debug --template %s --limit %d %C --rev %s %C', 127 '{node};{parents}\\n', 128 ($offset + $limit), // No '--skip' in Mercurial. 129 $branch_arg, 130 hgsprintf('reverse(ancestors(%s))', $commit_hash), 131 $path_arg); 132 133 $stdout = PhabricatorRepository::filterMercurialDebugOutput($stdout); 134 $lines = explode("\n", trim($stdout)); 135 $lines = array_slice($lines, $offset); 136 137 $hash_list = array(); 138 $parent_map = array(); 139 140 $last = null; 141 foreach (array_reverse($lines) as $line) { 142 list($hash, $parents) = explode(';', $line); 143 $parents = trim($parents); 144 if (!$parents) { 145 if ($last === null) { 146 $parent_map[$hash] = array('...'); 147 } else { 148 $parent_map[$hash] = array($last); 149 } 150 } else { 151 $parents = preg_split('/\s+/', $parents); 152 foreach ($parents as $parent) { 153 list($plocal, $phash) = explode(':', $parent); 154 if (!preg_match('/^0+$/', $phash)) { 155 $parent_map[$hash][] = $phash; 156 } 157 } 158 // This may happen for the zeroth commit in repository, both hashes 159 // are "000000000...". 160 if (empty($parent_map[$hash])) { 161 $parent_map[$hash] = array('...'); 162 } 163 } 164 165 // The rendering code expects the first commit to be "mainline", like 166 // Git. Flip the order so it does the right thing. 167 $parent_map[$hash] = array_reverse($parent_map[$hash]); 168 169 $hash_list[] = $hash; 170 $last = $hash; 171 } 172 173 $hash_list = array_reverse($hash_list); 174 $this->parents = $parent_map; 175 176 return DiffusionQuery::loadHistoryForCommitIdentifiers( 177 $hash_list, 178 $drequest); 179 } 180 181 protected function getSVNResult(ConduitAPIRequest $request) { 182 $drequest = $this->getDiffusionRequest(); 183 $repository = $drequest->getRepository(); 184 $commit = $request->getValue('commit'); 185 $path = $request->getValue('path'); 186 $offset = $request->getValue('offset'); 187 $limit = $request->getValue('limit'); 188 $need_direct_changes = $request->getValue('needDirectChanges'); 189 $need_child_changes = $request->getValue('needChildChanges'); 190 191 $conn_r = $repository->establishConnection('r'); 192 193 $paths = queryfx_all( 194 $conn_r, 195 'SELECT id, path FROM %T WHERE pathHash IN (%Ls)', 196 PhabricatorRepository::TABLE_PATH, 197 array(md5('/'.trim($path, '/')))); 198 $paths = ipull($paths, 'id', 'path'); 199 $path_id = idx($paths, '/'.trim($path, '/')); 200 201 if (!$path_id) { 202 return array(); 203 } 204 205 $filter_query = ''; 206 if ($need_direct_changes) { 207 if ($need_child_changes) { 208 $type = DifferentialChangeType::TYPE_CHILD; 209 $filter_query = 'AND (isDirect = 1 OR changeType = '.$type.')'; 210 } else { 211 $filter_query = 'AND (isDirect = 1)'; 212 } 213 } 214 215 $history_data = queryfx_all( 216 $conn_r, 217 'SELECT * FROM %T WHERE repositoryID = %d AND pathID = %d 218 AND commitSequence <= %d 219 %Q 220 ORDER BY commitSequence DESC 221 LIMIT %d, %d', 222 PhabricatorRepository::TABLE_PATHCHANGE, 223 $repository->getID(), 224 $path_id, 225 $commit ? $commit : 0x7FFFFFFF, 226 $filter_query, 227 $offset, 228 $limit); 229 230 $commits = array(); 231 $commit_data = array(); 232 233 $commit_ids = ipull($history_data, 'commitID'); 234 if ($commit_ids) { 235 $commits = id(new PhabricatorRepositoryCommit())->loadAllWhere( 236 'id IN (%Ld)', 237 $commit_ids); 238 if ($commits) { 239 $commit_data = id(new PhabricatorRepositoryCommitData())->loadAllWhere( 240 'commitID in (%Ld)', 241 $commit_ids); 242 $commit_data = mpull($commit_data, null, 'getCommitID'); 243 } 244 } 245 246 $history = array(); 247 foreach ($history_data as $row) { 248 $item = new DiffusionPathChange(); 249 250 $commit = idx($commits, $row['commitID']); 251 if ($commit) { 252 $item->setCommit($commit); 253 $item->setCommitIdentifier($commit->getCommitIdentifier()); 254 $data = idx($commit_data, $commit->getID()); 255 if ($data) { 256 $item->setCommitData($data); 257 } 258 } 259 260 $item->setChangeType($row['changeType']); 261 $item->setFileType($row['fileType']); 262 263 $history[] = $item; 264 } 265 266 return $history; 267 } 268 269 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |