[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 <?php 2 3 final class DifferentialChangesetViewController extends DifferentialController { 4 5 public function shouldAllowPublic() { 6 return true; 7 } 8 9 public function processRequest() { 10 $request = $this->getRequest(); 11 12 $author_phid = $request->getUser()->getPHID(); 13 14 $rendering_reference = $request->getStr('ref'); 15 $parts = explode('/', $rendering_reference); 16 if (count($parts) == 2) { 17 list($id, $vs) = $parts; 18 } else { 19 $id = $parts[0]; 20 $vs = 0; 21 } 22 23 $id = (int)$id; 24 $vs = (int)$vs; 25 26 $load_ids = array($id); 27 if ($vs && ($vs != -1)) { 28 $load_ids[] = $vs; 29 } 30 31 $changesets = id(new DifferentialChangesetQuery()) 32 ->setViewer($request->getUser()) 33 ->withIDs($load_ids) 34 ->needHunks(true) 35 ->execute(); 36 $changesets = mpull($changesets, null, 'getID'); 37 38 $changeset = idx($changesets, $id); 39 if (!$changeset) { 40 return new Aphront404Response(); 41 } 42 43 $vs_changeset = null; 44 if ($vs && ($vs != -1)) { 45 $vs_changeset = idx($changesets, $vs); 46 if (!$vs_changeset) { 47 return new Aphront404Response(); 48 } 49 } 50 51 $view = $request->getStr('view'); 52 if ($view) { 53 $phid = idx($changeset->getMetadata(), "$view:binary-phid"); 54 if ($phid) { 55 return id(new AphrontRedirectResponse())->setURI("/file/info/$phid/"); 56 } 57 switch ($view) { 58 case 'new': 59 return $this->buildRawFileResponse($changeset, $is_new = true); 60 case 'old': 61 if ($vs_changeset) { 62 return $this->buildRawFileResponse($vs_changeset, $is_new = true); 63 } 64 return $this->buildRawFileResponse($changeset, $is_new = false); 65 default: 66 return new Aphront400Response(); 67 } 68 } 69 70 if (!$vs) { 71 $right = $changeset; 72 $left = null; 73 74 $right_source = $right->getID(); 75 $right_new = true; 76 $left_source = $right->getID(); 77 $left_new = false; 78 79 $render_cache_key = $right->getID(); 80 } else if ($vs == -1) { 81 $right = null; 82 $left = $changeset; 83 84 $right_source = $left->getID(); 85 $right_new = false; 86 $left_source = $left->getID(); 87 $left_new = true; 88 89 $render_cache_key = null; 90 } else { 91 $right = $changeset; 92 $left = $vs_changeset; 93 94 $right_source = $right->getID(); 95 $right_new = true; 96 $left_source = $left->getID(); 97 $left_new = true; 98 99 $render_cache_key = null; 100 } 101 102 if ($left) { 103 $left_data = $left->makeNewFile(); 104 if ($right) { 105 $right_data = $right->makeNewFile(); 106 } else { 107 $right_data = $left->makeOldFile(); 108 } 109 110 $engine = new PhabricatorDifferenceEngine(); 111 $synthetic = $engine->generateChangesetFromFileContent( 112 $left_data, 113 $right_data); 114 115 $choice = clone nonempty($left, $right); 116 $choice->attachHunks($synthetic->getHunks()); 117 118 $changeset = $choice; 119 } 120 121 $coverage = null; 122 if ($right && $right->getDiffID()) { 123 $unit = id(new DifferentialDiffProperty())->loadOneWhere( 124 'diffID = %d AND name = %s', 125 $right->getDiffID(), 126 'arc:unit'); 127 128 if ($unit) { 129 $coverage = array(); 130 foreach ($unit->getData() as $result) { 131 $result_coverage = idx($result, 'coverage'); 132 if (!$result_coverage) { 133 continue; 134 } 135 $file_coverage = idx($result_coverage, $right->getFileName()); 136 if (!$file_coverage) { 137 continue; 138 } 139 $coverage[] = $file_coverage; 140 } 141 142 $coverage = ArcanistUnitTestResult::mergeCoverage($coverage); 143 } 144 } 145 146 $spec = $request->getStr('range'); 147 list($range_s, $range_e, $mask) = 148 DifferentialChangesetParser::parseRangeSpecification($spec); 149 150 $parser = new DifferentialChangesetParser(); 151 $parser->setCoverage($coverage); 152 $parser->setChangeset($changeset); 153 $parser->setRenderingReference($rendering_reference); 154 $parser->setRenderCacheKey($render_cache_key); 155 $parser->setRightSideCommentMapping($right_source, $right_new); 156 $parser->setLeftSideCommentMapping($left_source, $left_new); 157 $parser->setWhitespaceMode($request->getStr('whitespace')); 158 $parser->setCharacterEncoding($request->getStr('encoding')); 159 $parser->setHighlightAs($request->getStr('highlight')); 160 161 if ($request->getStr('renderer') == '1up') { 162 $parser->setRenderer(new DifferentialChangesetOneUpRenderer()); 163 } 164 165 166 if ($left && $right) { 167 $parser->setOriginals($left, $right); 168 } 169 170 // Load both left-side and right-side inline comments. 171 $inlines = $this->loadInlineComments( 172 array($left_source, $right_source), 173 $author_phid); 174 175 if ($left_new) { 176 $inlines = array_merge( 177 $inlines, 178 $this->buildLintInlineComments($left)); 179 } 180 181 if ($right_new) { 182 $inlines = array_merge( 183 $inlines, 184 $this->buildLintInlineComments($right)); 185 } 186 187 $phids = array(); 188 foreach ($inlines as $inline) { 189 $parser->parseInlineComment($inline); 190 if ($inline->getAuthorPHID()) { 191 $phids[$inline->getAuthorPHID()] = true; 192 } 193 } 194 $phids = array_keys($phids); 195 196 $handles = $this->loadViewerHandles($phids); 197 $parser->setHandles($handles); 198 199 $engine = new PhabricatorMarkupEngine(); 200 $engine->setViewer($request->getUser()); 201 202 foreach ($inlines as $inline) { 203 $engine->addObject( 204 $inline, 205 PhabricatorInlineCommentInterface::MARKUP_FIELD_BODY); 206 } 207 208 $engine->process(); 209 $parser->setMarkupEngine($engine); 210 211 if ($request->isAjax()) { 212 // TODO: This is sort of lazy, the effect is just to not render "Edit" 213 // and "Reply" links on the "standalone view". 214 $parser->setUser($request->getUser()); 215 } 216 217 $output = $parser->render($range_s, $range_e, $mask); 218 219 $mcov = $parser->renderModifiedCoverage(); 220 221 if ($request->isAjax()) { 222 $coverage = array( 223 'differential-mcoverage-'.md5($changeset->getFilename()) => $mcov, 224 ); 225 226 return id(new PhabricatorChangesetResponse()) 227 ->setRenderedChangeset($output) 228 ->setCoverage($coverage); 229 } 230 231 Javelin::initBehavior('differential-show-more', array( 232 'uri' => '/differential/changeset/', 233 'whitespace' => $request->getStr('whitespace'), 234 )); 235 236 Javelin::initBehavior('differential-comment-jump', array()); 237 238 // TODO: [HTML] Clean up DifferentialChangesetParser output, but it's 239 // undergoing like six kinds of refactoring anyway. 240 $output = phutil_safe_html($output); 241 242 $detail = new DifferentialChangesetDetailView(); 243 $detail->setChangeset($changeset); 244 $detail->appendChild($output); 245 $detail->setVsChangesetID($left_source); 246 247 $panel = new DifferentialPrimaryPaneView(); 248 $panel->appendChild( 249 phutil_tag( 250 'div', 251 array( 252 'class' => 'differential-review-stage', 253 'id' => 'differential-review-stage', 254 ), 255 $detail->render())); 256 257 $crumbs = $this->buildApplicationCrumbs(); 258 259 $revision_id = $changeset->getDiff()->getRevisionID(); 260 if ($revision_id) { 261 $crumbs->addTextCrumb('D'.$revision_id, '/D'.$revision_id); 262 } 263 264 $diff_id = $changeset->getDiff()->getID(); 265 if ($diff_id) { 266 $crumbs->addTextCrumb( 267 pht('Diff %d', $diff_id), 268 $this->getApplicationURI('diff/'.$diff_id)); 269 } 270 271 $crumbs->addTextCrumb($changeset->getDisplayFilename()); 272 273 $box = id(new PHUIObjectBoxView()) 274 ->setHeaderText(pht('Standalone View')) 275 ->appendChild($panel); 276 277 return $this->buildApplicationPage( 278 array( 279 $crumbs, 280 $box, 281 ), 282 array( 283 'title' => pht('Changeset View'), 284 'device' => false, 285 )); 286 } 287 288 private function loadInlineComments(array $changeset_ids, $author_phid) { 289 $changeset_ids = array_unique(array_filter($changeset_ids)); 290 if (!$changeset_ids) { 291 return; 292 } 293 294 return id(new DifferentialInlineCommentQuery()) 295 ->withViewerAndChangesetIDs($author_phid, $changeset_ids) 296 ->execute(); 297 } 298 299 private function buildRawFileResponse( 300 DifferentialChangeset $changeset, 301 $is_new) { 302 303 $viewer = $this->getRequest()->getUser(); 304 305 if ($is_new) { 306 $key = 'raw:new:phid'; 307 } else { 308 $key = 'raw:old:phid'; 309 } 310 311 $metadata = $changeset->getMetadata(); 312 313 $file = null; 314 $phid = idx($metadata, $key); 315 if ($phid) { 316 $file = id(new PhabricatorFileQuery()) 317 ->setViewer($viewer) 318 ->withPHIDs(array($phid)) 319 ->execute(); 320 if ($file) { 321 $file = head($file); 322 } 323 } 324 325 if (!$file) { 326 // This is just building a cache of the changeset content in the file 327 // tool, and is safe to run on a read pathway. 328 $unguard = AphrontWriteGuard::beginScopedUnguardedWrites(); 329 330 if ($is_new) { 331 $data = $changeset->makeNewFile(); 332 } else { 333 $data = $changeset->makeOldFile(); 334 } 335 336 $file = PhabricatorFile::newFromFileData( 337 $data, 338 array( 339 'name' => $changeset->getFilename(), 340 'mime-type' => 'text/plain', 341 )); 342 343 $metadata[$key] = $file->getPHID(); 344 $changeset->setMetadata($metadata); 345 $changeset->save(); 346 347 unset($unguard); 348 } 349 350 return $file->getRedirectResponse(); 351 } 352 353 private function buildLintInlineComments($changeset) { 354 $lint = id(new DifferentialDiffProperty())->loadOneWhere( 355 'diffID = %d AND name = %s', 356 $changeset->getDiffID(), 357 'arc:lint'); 358 if (!$lint) { 359 return array(); 360 } 361 $lint = $lint->getData(); 362 363 $inlines = array(); 364 foreach ($lint as $msg) { 365 if ($msg['path'] != $changeset->getFilename()) { 366 continue; 367 } 368 $inline = new DifferentialInlineComment(); 369 $inline->setChangesetID($changeset->getID()); 370 $inline->setIsNewFile(1); 371 $inline->setSyntheticAuthor('Lint: '.$msg['name']); 372 $inline->setLineNumber($msg['line']); 373 $inline->setLineLength(0); 374 375 $inline->setContent('%%%'.$msg['description'].'%%%'); 376 377 $inlines[] = $inline; 378 } 379 380 return $inlines; 381 } 382 383 }
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 |