2011-01-24 22:18:41 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/*
|
2012-01-16 07:25:53 +01:00
|
|
|
* Copyright 2012 Facebook, Inc.
|
2011-01-24 22:18:41 +01:00
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
final class DifferentialDiffTableOfContentsView extends AphrontView {
|
|
|
|
|
|
|
|
private $changesets = array();
|
2012-03-15 18:45:35 +01:00
|
|
|
private $visibleChangesets = array();
|
2012-03-01 08:16:45 +01:00
|
|
|
private $repository;
|
|
|
|
private $diff;
|
|
|
|
private $user;
|
2011-04-15 23:25:23 +02:00
|
|
|
private $standaloneViewLink = null;
|
|
|
|
private $renderURI = '/differential/changeset/';
|
|
|
|
private $revisionID;
|
2011-04-28 06:16:35 +02:00
|
|
|
private $whitespace;
|
2012-03-13 01:06:55 +01:00
|
|
|
private $unitTestData;
|
2011-01-24 22:18:41 +01:00
|
|
|
|
|
|
|
public function setChangesets($changesets) {
|
|
|
|
$this->changesets = $changesets;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2012-03-15 18:45:35 +01:00
|
|
|
public function setVisibleChangesets($visible_changesets) {
|
|
|
|
$this->visibleChangesets = $visible_changesets;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2012-03-01 08:16:45 +01:00
|
|
|
public function setRepository(PhabricatorRepository $repository) {
|
|
|
|
$this->repository = $repository;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setDiff(DifferentialDiff $diff) {
|
|
|
|
$this->diff = $diff;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2012-03-13 01:06:55 +01:00
|
|
|
public function setUnitTestData($unit_test_data) {
|
|
|
|
$this->unitTestData = $unit_test_data;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2012-03-01 08:16:45 +01:00
|
|
|
public function setUser(PhabricatorUser $user) {
|
|
|
|
$this->user = $user;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-04-15 23:25:23 +02:00
|
|
|
public function setStandaloneViewLink($standalone_view_link) {
|
|
|
|
$this->standaloneViewLink = $standalone_view_link;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setVsMap(array $vs_map) {
|
|
|
|
$this->vsMap = $vs_map;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setRevisionID($revision_id) {
|
|
|
|
$this->revisionID = $revision_id;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-04-28 06:16:35 +02:00
|
|
|
public function setWhitespace($whitespace) {
|
|
|
|
$this->whitespace = $whitespace;
|
|
|
|
return $this;
|
|
|
|
}
|
2011-04-15 23:25:23 +02:00
|
|
|
|
2011-01-24 22:18:41 +01:00
|
|
|
public function render() {
|
2011-01-27 23:55:52 +01:00
|
|
|
|
|
|
|
require_celerity_resource('differential-core-view-css');
|
2011-01-25 20:57:47 +01:00
|
|
|
require_celerity_resource('differential-table-of-contents-css');
|
2011-01-24 22:18:41 +01:00
|
|
|
|
|
|
|
$rows = array();
|
|
|
|
|
2012-03-13 01:06:55 +01:00
|
|
|
$coverage = array();
|
|
|
|
if ($this->unitTestData) {
|
|
|
|
$coverage_by_file = array();
|
|
|
|
foreach ($this->unitTestData as $result) {
|
|
|
|
$test_coverage = idx($result, 'coverage');
|
|
|
|
if (!$test_coverage) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
foreach ($test_coverage as $file => $results) {
|
|
|
|
$coverage_by_file[$file][] = $results;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
foreach ($coverage_by_file as $file => $coverages) {
|
|
|
|
$coverage[$file] = ArcanistUnitTestResult::mergeCoverage($coverages);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-24 22:18:41 +01:00
|
|
|
$changesets = $this->changesets;
|
2012-03-01 08:16:45 +01:00
|
|
|
$paths = array();
|
2012-03-15 18:45:35 +01:00
|
|
|
foreach ($changesets as $id => $changeset) {
|
2011-01-24 22:18:41 +01:00
|
|
|
$type = $changeset->getChangeType();
|
|
|
|
$ftype = $changeset->getFileType();
|
2012-01-24 09:37:50 +01:00
|
|
|
$link = $this->renderChangesetLink($changeset);
|
2012-01-16 07:43:54 +01:00
|
|
|
|
2011-01-24 22:18:41 +01:00
|
|
|
if (DifferentialChangeType::isOldLocationChangeType($type)) {
|
|
|
|
$away = $changeset->getAwayPaths();
|
|
|
|
if (count($away) > 1) {
|
|
|
|
$meta = array();
|
|
|
|
if ($type == DifferentialChangeType::TYPE_MULTICOPY) {
|
|
|
|
$meta[] = 'Deleted after being copied to multiple locations:';
|
|
|
|
} else {
|
|
|
|
$meta[] = 'Copied to multiple locations:';
|
|
|
|
}
|
|
|
|
foreach ($away as $path) {
|
2012-01-16 07:25:53 +01:00
|
|
|
$meta[] = phutil_escape_html($path);
|
2011-01-24 22:18:41 +01:00
|
|
|
}
|
|
|
|
$meta = implode('<br />', $meta);
|
|
|
|
} else {
|
|
|
|
if ($type == DifferentialChangeType::TYPE_MOVE_AWAY) {
|
2012-01-16 07:25:53 +01:00
|
|
|
$meta = 'Moved to '.phutil_escape_html(reset($away));
|
2011-01-24 22:18:41 +01:00
|
|
|
} else {
|
2012-01-16 07:25:53 +01:00
|
|
|
$meta = 'Copied to '.phutil_escape_html(reset($away));
|
2011-01-24 22:18:41 +01:00
|
|
|
}
|
|
|
|
}
|
2012-01-16 07:43:54 +01:00
|
|
|
} else if ($type == DifferentialChangeType::TYPE_MOVE_HERE) {
|
|
|
|
$meta = 'Moved from '.phutil_escape_html($changeset->getOldFile());
|
|
|
|
} else if ($type == DifferentialChangeType::TYPE_COPY_HERE) {
|
|
|
|
$meta = 'Copied from '.phutil_escape_html($changeset->getOldFile());
|
2011-01-24 22:18:41 +01:00
|
|
|
} else {
|
2012-01-16 07:43:54 +01:00
|
|
|
$meta = null;
|
2011-01-24 22:18:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$line_count = $changeset->getAffectedLineCount();
|
|
|
|
if ($line_count == 0) {
|
|
|
|
$lines = null;
|
|
|
|
} else if ($line_count == 1) {
|
|
|
|
$lines = ' (1 line)';
|
|
|
|
} else {
|
|
|
|
$lines = ' ('.$line_count.' lines)';
|
|
|
|
}
|
|
|
|
|
|
|
|
$char = DifferentialChangeType::getSummaryCharacterForChangeType($type);
|
|
|
|
$chartitle = DifferentialChangeType::getFullNameForChangeType($type);
|
|
|
|
$desc = DifferentialChangeType::getShortNameForFileType($ftype);
|
|
|
|
if ($desc) {
|
|
|
|
$desc = '('.$desc.')';
|
|
|
|
}
|
|
|
|
$pchar =
|
|
|
|
($changeset->getOldProperties() === $changeset->getNewProperties())
|
|
|
|
? null
|
|
|
|
: '<span title="Properties Changed">M</span>';
|
|
|
|
|
2012-03-13 01:06:55 +01:00
|
|
|
$fname = $changeset->getFilename();
|
|
|
|
$cov = $this->renderCoverage($coverage, $fname);
|
|
|
|
if ($cov === null) {
|
|
|
|
$mcov = $cov = '<em>-</em>';
|
|
|
|
} else {
|
|
|
|
$mcov = phutil_render_tag(
|
|
|
|
'div',
|
|
|
|
array(
|
|
|
|
'id' => 'differential-mcoverage-'.md5($fname),
|
|
|
|
'class' => 'differential-mcoverage-loading',
|
|
|
|
),
|
2012-03-15 18:45:35 +01:00
|
|
|
(isset($this->visibleChangesets[$id]) ? 'Loading...' : '?'));
|
2012-03-13 01:06:55 +01:00
|
|
|
}
|
|
|
|
|
2011-01-24 22:18:41 +01:00
|
|
|
$rows[] =
|
|
|
|
'<tr>'.
|
2011-04-15 23:25:23 +02:00
|
|
|
'<td class="differential-toc-char" title='.$chartitle.'>'.$char.
|
|
|
|
'</td>'.
|
2011-01-24 22:18:41 +01:00
|
|
|
'<td class="differential-toc-prop">'.$pchar.'</td>'.
|
|
|
|
'<td class="differential-toc-ftype">'.$desc.'</td>'.
|
|
|
|
'<td class="differential-toc-file">'.$link.$lines.'</td>'.
|
2012-03-13 01:06:55 +01:00
|
|
|
'<td class="differential-toc-cov">'.$cov.'</td>'.
|
|
|
|
'<td class="differential-toc-mcov">'.$mcov.'</td>'.
|
2011-01-24 22:18:41 +01:00
|
|
|
'</tr>';
|
|
|
|
if ($meta) {
|
|
|
|
$rows[] =
|
|
|
|
'<tr>'.
|
2011-01-26 00:19:06 +01:00
|
|
|
'<td colspan="3"></td>'.
|
2011-01-24 22:18:41 +01:00
|
|
|
'<td class="differential-toc-meta">'.$meta.'</td>'.
|
|
|
|
'</tr>';
|
|
|
|
}
|
2012-03-01 08:16:45 +01:00
|
|
|
if ($this->diff && $this->repository) {
|
|
|
|
$paths[] =
|
|
|
|
$changeset->getAbsoluteRepositoryPath($this->diff, $this->repository);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$editor_link = null;
|
|
|
|
if ($paths && $this->user) {
|
|
|
|
$editor_link = $this->user->loadEditorLink(
|
|
|
|
implode(' ', $paths),
|
|
|
|
1, // line number
|
2012-04-05 02:53:16 +02:00
|
|
|
$this->repository->getCallsign());
|
2012-03-01 08:16:45 +01:00
|
|
|
if ($editor_link) {
|
|
|
|
$editor_link = phutil_render_tag(
|
|
|
|
'a',
|
|
|
|
array(
|
|
|
|
'href' => $editor_link,
|
|
|
|
'class' => 'button differential-toc-edit-all',
|
|
|
|
),
|
|
|
|
'Open All in Editor');
|
|
|
|
}
|
2011-01-24 22:18:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return
|
2011-01-27 23:55:52 +01:00
|
|
|
'<div class="differential-toc differential-panel">'.
|
2012-03-01 08:16:45 +01:00
|
|
|
$editor_link.
|
2011-01-24 22:18:41 +01:00
|
|
|
'<h1>Table of Contents</h1>'.
|
|
|
|
'<table>'.
|
2012-03-13 01:06:55 +01:00
|
|
|
'<tr>'.
|
|
|
|
'<th></th>'.
|
|
|
|
'<th></th>'.
|
|
|
|
'<th></th>'.
|
|
|
|
'<th>Path</th>'.
|
|
|
|
'<th class="differential-toc-cov">Coverage (All)</th>'.
|
|
|
|
'<th class="differential-toc-mcov">Coverage (Touched)</th>'.
|
|
|
|
'</tr>'.
|
2011-01-24 22:18:41 +01:00
|
|
|
implode("\n", $rows).
|
|
|
|
'</table>'.
|
|
|
|
'</div>';
|
|
|
|
}
|
2012-01-24 09:37:50 +01:00
|
|
|
|
2012-03-13 01:06:55 +01:00
|
|
|
private function renderCoverage(array $coverage, $file) {
|
|
|
|
$info = idx($coverage, $file);
|
|
|
|
if (!$info) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
$not_covered = substr_count($info, 'U');
|
|
|
|
$covered = substr_count($info, 'C');
|
|
|
|
|
|
|
|
if (!$not_covered && !$covered) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return sprintf('%d%%', 100 * ($covered / ($covered + $not_covered)));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-24 09:37:50 +01:00
|
|
|
private function renderChangesetLink(DifferentialChangeset $changeset) {
|
|
|
|
$display_file = $changeset->getDisplayFilename();
|
|
|
|
|
|
|
|
if ($this->standaloneViewLink) {
|
|
|
|
$id = $changeset->getID();
|
|
|
|
$vs_id = idx($this->vsMap, $id);
|
|
|
|
|
|
|
|
$ref = $vs_id ? $id.'/'.$vs_id : $id;
|
|
|
|
$detail_uri = new PhutilURI($this->renderURI);
|
|
|
|
$detail_uri->setQueryParams(
|
|
|
|
array(
|
|
|
|
'ref' => $ref,
|
|
|
|
'whitespace' => $this->whitespace,
|
|
|
|
'revision_id' => $this->revisionID,
|
|
|
|
));
|
|
|
|
|
|
|
|
return phutil_render_tag(
|
|
|
|
'a',
|
|
|
|
array(
|
|
|
|
'href' => $detail_uri,
|
|
|
|
'target' => '_blank',
|
|
|
|
),
|
|
|
|
phutil_escape_html($display_file));
|
|
|
|
}
|
|
|
|
return phutil_render_tag(
|
|
|
|
'a',
|
|
|
|
array(
|
|
|
|
'href' => '#'.$changeset->getAnchorName(),
|
|
|
|
),
|
|
|
|
phutil_escape_html($display_file));
|
|
|
|
}
|
2012-03-30 19:13:08 +02:00
|
|
|
|
2011-01-24 22:18:41 +01:00
|
|
|
}
|