Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/diffusion/controller/DiffusionBrowseFileController.php b/src/applications/diffusion/controller/DiffusionBrowseFileController.php
index be92f51533..b01b3d02a8 100644
--- a/src/applications/diffusion/controller/DiffusionBrowseFileController.php
+++ b/src/applications/diffusion/controller/DiffusionBrowseFileController.php
@@ -1,1020 +1,1021 @@
<?php
final class DiffusionBrowseFileController extends DiffusionController {
private $corpusType = 'text';
private $lintCommit;
private $lintMessages;
public function processRequest() {
$request = $this->getRequest();
$drequest = $this->getDiffusionRequest();
$before = $request->getStr('before');
if ($before) {
return $this->buildBeforeResponse($before);
}
$path = $drequest->getPath();
$selected = $request->getStr('view');
$preferences = $request->getUser()->loadPreferences();
if (!$selected) {
$selected = $preferences->getPreference(
PhabricatorUserPreferences::PREFERENCE_DIFFUSION_VIEW,
'highlighted');
} else if ($request->isFormPost() && $selected != 'raw') {
$preferences->setPreference(
PhabricatorUserPreferences::PREFERENCE_DIFFUSION_VIEW,
$selected);
$preferences->save();
return id(new AphrontRedirectResponse())
->setURI($request->getRequestURI()->alter('view', $selected));
}
$needs_blame = ($selected == 'blame' || $selected == 'plainblame');
$file_query = DiffusionFileContentQuery::newFromDiffusionRequest(
$this->diffusionRequest);
$file_query->setViewer($request->getUser());
$file_query->setNeedsBlame($needs_blame);
$file_query->loadFileContent();
$data = $file_query->getRawData();
if ($selected === 'raw') {
return $this->buildRawResponse($path, $data);
}
$this->loadLintMessages();
// Build the content of the file.
$corpus = $this->buildCorpus(
$selected,
$file_query,
$needs_blame,
$drequest,
$path,
$data);
require_celerity_resource('diffusion-source-css');
if ($this->corpusType == 'text') {
$view_select_panel = $this->renderViewSelectPanel($selected);
} else {
$view_select_panel = null;
}
// Render the page.
$content = array();
$content[] = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'browse',
));
$follow = $request->getStr('follow');
if ($follow) {
$notice = new AphrontErrorView();
$notice->setSeverity(AphrontErrorView::SEVERITY_WARNING);
$notice->setTitle('Unable to Continue');
switch ($follow) {
case 'first':
$notice->appendChild(
"Unable to continue tracing the history of this file because ".
"this commit is the first commit in the repository.");
break;
case 'created':
$notice->appendChild(
"Unable to continue tracing the history of this file because ".
"this commit created the file.");
break;
}
$content[] = $notice;
}
$renamed = $request->getStr('renamed');
if ($renamed) {
$notice = new AphrontErrorView();
$notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
$notice->setTitle('File Renamed');
$notice->appendChild(
"File history passes through a rename from '".
phutil_escape_html($drequest->getPath())."' to '".
phutil_escape_html($renamed)."'.");
$content[] = $notice;
}
$content[] = $view_select_panel;
$content[] = $corpus;
$content[] = $this->buildOpenRevisions();
$nav = $this->buildSideNav('browse', true);
$nav->appendChild($content);
$basename = basename($this->getDiffusionRequest()->getPath());
return $this->buildStandardPageResponse(
$nav,
array(
'title' => $basename,
));
}
private function loadLintMessages() {
$drequest = $this->getDiffusionRequest();
$branch = $drequest->loadBranch();
if (!$branch || !$branch->getLintCommit()) {
return;
}
$file_history = DiffusionHistoryQuery::newFromDiffusionRequest(
$drequest)->setLimit(1)->loadHistory();
$lint_request = clone $drequest;
$lint_request->setCommit($branch->getLintCommit());
$lint_history = DiffusionHistoryQuery::newFromDiffusionRequest(
$lint_request)->setLimit(1)->loadHistory();
$this->lintCommit = '';
if (!$file_history || !$lint_history ||
reset($file_history)->getCommitIdentifier() !=
reset($lint_history)->getCommitIdentifier()) {
$this->lintCommit = $branch->getLintCommit();
}
$conn = id(new PhabricatorRepository())->establishConnection('r');
$where = '';
if ($drequest->getLint()) {
$where = qsprintf(
$conn,
'AND code = %s',
$drequest->getLint());
}
$this->lintMessages = queryfx_all(
$conn,
'SELECT * FROM %T WHERE branchID = %d %Q AND path = %s',
PhabricatorRepository::TABLE_LINTMESSAGE,
$branch->getID(),
$where,
'/'.$drequest->getPath());
}
private function buildCorpus($selected,
DiffusionFileContentQuery $file_query,
$needs_blame,
DiffusionRequest $drequest,
$path,
$data) {
if (ArcanistDiffUtils::isHeuristicBinaryFile($data)) {
$file = $this->loadFileForData($path, $data);
$file_uri = $file->getBestURI();
if ($file->isViewableImage()) {
$this->corpusType = 'image';
return $this->buildImageCorpus($file_uri);
} else {
$this->corpusType = 'binary';
return $this->buildBinaryCorpus($file_uri, $data);
}
}
switch ($selected) {
case 'plain':
$style =
"margin: 1em 2em; width: 90%; height: 80em; font-family: monospace";
$corpus = phutil_render_tag(
'textarea',
array(
'style' => $style,
),
phutil_escape_html($file_query->getRawData()));
break;
case 'plainblame':
$style =
"margin: 1em 2em; width: 90%; height: 80em; font-family: monospace";
list($text_list, $rev_list, $blame_dict) =
$file_query->getBlameData();
$rows = array();
foreach ($text_list as $k => $line) {
$rev = $rev_list[$k];
if (isset($blame_dict[$rev]['handle'])) {
$author = $blame_dict[$rev]['handle']->getName();
} else {
$author = $blame_dict[$rev]['author'];
}
$rows[] =
sprintf("%-10s %-20s %s", substr($rev, 0, 7), $author, $line);
}
$corpus = phutil_render_tag(
'textarea',
array(
'style' => $style,
),
phutil_escape_html(implode("\n", $rows)));
break;
case 'highlighted':
case 'blame':
default:
require_celerity_resource('syntax-highlighting-css');
list($text_list, $rev_list, $blame_dict) = $file_query->getBlameData();
$text_list = implode("\n", $text_list);
$text_list = PhabricatorSyntaxHighlighter::highlightWithFilename(
$path,
$text_list);
$text_list = explode("\n", $text_list);
$rows = $this->buildDisplayRows($text_list, $rev_list, $blame_dict,
$needs_blame, $drequest, $file_query, $selected);
$id = celerity_generate_unique_node_id();
$projects = $drequest->loadArcanistProjects();
$langs = array();
foreach ($projects as $project) {
$ls = $project->getSymbolIndexLanguages();
if (!$ls) {
continue;
}
$dep_projects = $project->getSymbolIndexProjects();
$dep_projects[] = $project->getPHID();
foreach ($ls as $lang) {
if (!isset($langs[$lang])) {
$langs[$lang] = array();
}
$langs[$lang] += $dep_projects + array($project);
}
}
$lang = last(explode('.', $drequest->getPath()));
$prefs = $this->getRequest()->getUser()->loadPreferences();
$pref_symbols = $prefs->getPreference(
PhabricatorUserPreferences::PREFERENCE_DIFFUSION_SYMBOLS);
if (isset($langs[$lang]) && $pref_symbols != 'disabled') {
Javelin::initBehavior(
'repository-crossreference',
array(
'container' => $id,
'lang' => $lang,
'projects' => $langs[$lang],
));
}
$corpus_table = javelin_render_tag(
'table',
array(
'class' => "diffusion-source remarkup-code PhabricatorMonospaced",
'sigil' => 'diffusion-source',
),
implode("\n", $rows));
$corpus = phutil_render_tag(
'div',
array(
'style' => 'padding: 0 2em;',
'id' => $id,
),
$corpus_table);
break;
}
return $corpus;
}
private function renderViewSelectPanel($selected) {
$toggle_blame = array(
'highlighted' => 'blame',
'blame' => 'highlighted',
'plain' => 'plainblame',
'plainblame' => 'plain',
'raw' => 'raw', // not a real case.
);
$toggle_highlight = array(
'highlighted' => 'plain',
'blame' => 'plainblame',
'plain' => 'highlighted',
'plainblame' => 'blame',
'raw' => 'raw', // not a real case.
);
$user = $this->getRequest()->getUser();
$base_uri = $this->getRequest()->getRequestURI();
$blame_on = ($selected == 'blame' || $selected == 'plainblame');
if ($blame_on) {
$blame_text = pht('Disable Blame');
} else {
$blame_text = pht('Enable Blame');
}
$blame_button = $this->createViewAction(
$blame_text,
$base_uri->alter('view', $toggle_blame[$selected]),
$user);
$highlight_on = ($selected == 'blame' || $selected == 'highlighted');
if ($highlight_on) {
$highlight_text = pht('Disable Highlighting');
} else {
$highlight_text = pht('Enable Highlighting');
}
$highlight_button = $this->createViewAction(
$highlight_text,
$base_uri->alter('view', $toggle_highlight[$selected]),
$user);
$href = null;
if ($this->getRequest()->getStr('lint') !== null) {
$lint_text = pht('Hide %d Lint Message(s)', count($this->lintMessages));
$href = $base_uri->alter('lint', null);
} else if ($this->lintCommit === null) {
$lint_text = pht('Lint not Available');
} else if ($this->lintCommit) {
$lint_text = pht(
'Switch for %d Lint Message(s)',
count($this->lintMessages));
$href = $this->getDiffusionRequest()->generateURI(array(
'action' => 'browse',
'commit' => $this->lintCommit,
))->alter('lint', '');
} else if (!$this->lintMessages) {
$lint_text = pht('No Lint Messages');
} else {
$lint_text = pht('Show %d Lint Message(s)', count($this->lintMessages));
$href = $base_uri->alter('lint', '');
}
$lint_button = $this->createViewAction(
$lint_text,
$href,
$user);
if (!$href) {
$lint_button->setDisabled(true);
}
$raw_button = $this->createViewAction(
pht('View Raw File'),
$base_uri->alter('view', 'raw'),
$user,
'file');
$edit_button = $this->createEditAction();
return id(new PhabricatorActionListView())
->setUser($user)
->addAction($blame_button)
->addAction($highlight_button)
->addAction($lint_button)
->addAction($raw_button)
->addAction($edit_button);
}
private function createViewAction(
$localized_text,
$href,
$user,
$icon = null) {
return id(new PhabricatorActionView())
->setName($localized_text)
->setIcon($icon)
->setUser($user)
->setRenderAsForm(true)
->setHref($href);
}
private function createEditAction() {
$request = $this->getRequest();
$user = $request->getUser();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$path = $drequest->getPath();
$line = nonempty((int)$drequest->getLine(), 1);
$callsign = $repository->getCallsign();
$editor_link = $user->loadEditorLink($path, $line, $callsign);
$action = id(new PhabricatorActionView())
->setName(pht('Open in Editor'))
->setIcon('edit');
$action->setHref($editor_link);
$action->setDisabled(!$editor_link);
return $action;
}
private function buildDisplayRows(
array $text_list,
array $rev_list,
array $blame_dict,
$needs_blame,
DiffusionRequest $drequest,
DiffusionFileContentQuery $file_query,
$selected) {
if ($blame_dict) {
$epoch_list = ipull(ifilter($blame_dict, 'epoch'), 'epoch');
$epoch_min = min($epoch_list);
$epoch_max = max($epoch_list);
$epoch_range = ($epoch_max - $epoch_min) + 1;
}
$line_arr = array();
$line_str = $drequest->getLine();
$ranges = explode(',', $line_str);
foreach ($ranges as $range) {
if (strpos($range, '-') !== false) {
list($min, $max) = explode('-', $range, 2);
$line_arr[] = array(
'min' => min($min, $max),
'max' => max($min, $max),
);
} else if (strlen($range)) {
$line_arr[] = array(
'min' => $range,
'max' => $range,
);
}
}
$display = array();
$line_number = 1;
$last_rev = null;
$color = null;
foreach ($text_list as $k => $line) {
$display_line = array(
'color' => null,
'epoch' => null,
'commit' => null,
'author' => null,
'target' => null,
'highlighted' => null,
'line' => $line_number,
'data' => $line,
);
if ($needs_blame) {
// If the line's rev is same as the line above, show empty content
// with same color; otherwise generate blame info. The newer a change
// is, the more saturated the color.
// TODO: SVN doesn't always give us blame for the last line, if empty?
// Bug with our stuff or with SVN?
$rev = idx($rev_list, $k, $last_rev);
if ($last_rev == $rev) {
$display_line['color'] = $color;
} else {
$blame = $blame_dict[$rev];
if (!isset($blame['epoch'])) {
$color = '#ffd'; // Render as warning.
} else {
$color_ratio = ($blame['epoch'] - $epoch_min) / $epoch_range;
$color_value = 0xF6 * (1.0 - $color_ratio);
$color = sprintf(
'#%02x%02x%02x',
$color_value,
0xF6,
$color_value);
}
$display_line['epoch'] = idx($blame, 'epoch');
$display_line['color'] = $color;
$display_line['commit'] = $rev;
if (isset($blame['handle'])) {
$author_link = $blame['handle']->renderLink();
} else {
$author_link = phutil_render_tag(
'span',
array(
),
phutil_escape_html($blame['author']));
}
$display_line['author'] = $author_link;
$last_rev = $rev;
}
}
if ($line_arr) {
if ($line_number == $line_arr[0]['min']) {
$display_line['target'] = true;
}
foreach ($line_arr as $range) {
if ($line_number >= $range['min'] &&
$line_number <= $range['max']) {
$display_line['highlighted'] = true;
}
}
}
$display[] = $display_line;
++$line_number;
}
$commits = array_filter(ipull($display, 'commit'));
if ($commits) {
$commits = id(new PhabricatorAuditCommitQuery())
->withIdentifiers($drequest->getRepository()->getID(), $commits)
->needCommitData(true)
->execute();
$commits = mpull($commits, null, 'getCommitIdentifier');
}
$revision_ids = id(new DifferentialRevision())
->loadIDsByCommitPHIDs(mpull($commits, 'getPHID'));
$revisions = array();
if ($revision_ids) {
$revisions = id(new DifferentialRevision())->loadAllWhere(
'id IN (%Ld)',
$revision_ids);
}
$request = $this->getRequest();
$user = $request->getUser();
Javelin::initBehavior('phabricator-oncopy', array());
$engine = null;
$inlines = array();
if ($this->getRequest()->getStr('lint') !== null && $this->lintMessages) {
$engine = new PhabricatorMarkupEngine();
$engine->setViewer($user);
foreach ($this->lintMessages as $message) {
$inline = id(new PhabricatorAuditInlineComment())
+ ->setID($message['id'])
->setSyntheticAuthor(
ArcanistLintSeverity::getStringForSeverity($message['severity']).
' '.$message['code'].' ('.$message['name'].')')
->setLineNumber($message['line'])
->setContent($message['description']);
$inlines[$message['line']][] = $inline;
$engine->addObject(
$inline,
PhabricatorInlineCommentInterface::MARKUP_FIELD_BODY);
}
$engine->process();
require_celerity_resource('differential-changeset-view-css');
}
$rows = $this->renderInlines(
idx($inlines, 0, array()),
$needs_blame,
$engine);
foreach ($display as $line) {
$line_href = $drequest->generateURI(
array(
'action' => 'browse',
'line' => $line['line'],
'stable' => true,
));
$blame = array();
if ($line['color']) {
$color = $line['color'];
$before_link = null;
$commit_link = null;
$revision_link = null;
if (idx($line, 'commit')) {
$commit = $line['commit'];
$summary = 'Unknown';
if (idx($commits, $commit)) {
$summary = $commits[$commit]->getCommitData()->getSummary();
}
$tooltip = phabricator_date(
$line['epoch'],
$user)." \xC2\xB7 ".$summary;
Javelin::initBehavior('phabricator-tooltips', array());
require_celerity_resource('aphront-tooltip-css');
$commit_link = javelin_render_tag(
'a',
array(
'href' => $drequest->generateURI(
array(
'action' => 'commit',
'commit' => $line['commit'],
)),
'sigil' => 'has-tooltip',
'meta' => array(
'tip' => $tooltip,
'align' => 'E',
'size' => 600,
),
),
phutil_escape_html(phutil_utf8_shorten($line['commit'], 9, '')));
$revision_id = null;
if (idx($commits, $commit)) {
$revision_id = idx($revision_ids, $commits[$commit]->getPHID());
}
if ($revision_id) {
$revision = idx($revisions, $revision_id);
if (!$revision) {
$tooltip = '(Invalid revision)';
} else {
$tooltip =
phabricator_date($revision->getDateModified(), $user).
" \xC2\xB7 ".
$revision->getTitle();
}
$revision_link = javelin_render_tag(
'a',
array(
'href' => '/D'.$revision_id,
'sigil' => 'has-tooltip',
'meta' => array(
'tip' => $tooltip,
'align' => 'E',
'size' => 600,
),
),
'D'.$revision_id);
}
$uri = $line_href->alter('before', $commit);
$before_link = javelin_render_tag(
'a',
array(
'href' => $uri->setQueryParam('view', 'blame'),
'sigil' => 'has-tooltip',
'meta' => array(
'tip' => 'Skip Past This Commit',
'align' => 'E',
'size' => 300,
),
),
"\xC2\xAB");
}
$blame[] = phutil_render_tag(
'th',
array(
'class' => 'diffusion-blame-link',
'style' => 'background: '.$color,
),
$before_link);
$blame[] = phutil_render_tag(
'th',
array(
'class' => 'diffusion-rev-link',
'style' => 'background: '.$color,
),
$commit_link);
$blame[] = phutil_render_tag(
'th',
array(
'class' => 'diffusion-rev-link',
'style' => 'background: '.$color,
),
$revision_link);
$blame[] = phutil_render_tag(
'th',
array(
'class' => 'diffusion-author-link',
'style' => 'background: '.$color,
),
idx($line, 'author'));
}
$line_link = phutil_render_tag(
'a',
array(
'href' => $line_href,
),
phutil_escape_html($line['line']));
$blame[] = javelin_render_tag(
'th',
array(
'class' => 'diffusion-line-link',
'sigil' => 'diffusion-line-link',
'style' => isset($color) ? 'background: '.$color : null,
),
$line_link);
Javelin::initBehavior('diffusion-line-linker');
$blame = implode('', $blame);
if ($line['target']) {
Javelin::initBehavior(
'diffusion-jump-to',
array(
'target' => 'scroll_target',
));
$anchor_text = '<a id="scroll_target"></a>';
} else {
$anchor_text = null;
}
$line_text = phutil_render_tag(
'td',
array(
),
$anchor_text.
"\xE2\x80\x8B". // NOTE: See phabricator-oncopy behavior.
$line['data']);
$rows[] = phutil_render_tag(
'tr',
array(
'class' => ($line['highlighted'] ? 'highlighted' : null),
),
$blame.
$line_text);
$rows = array_merge($rows, $this->renderInlines(
idx($inlines, $line['line'], array()),
$needs_blame,
$engine));
}
return $rows;
}
private function renderInlines(array $inlines, $needs_blame, $engine) {
$rows = array();
foreach ($inlines as $inline) {
$inline_view = id(new DifferentialInlineCommentView())
->setMarkupEngine($engine)
->setInlineComment($inline)
->render();
$rows[] =
'<tr class="inline">'.
str_repeat('<th></th>', ($needs_blame ? 5 : 1)).
'<td>'.$inline_view.'</td>'.
'</tr>';
}
return $rows;
}
private static function renderRevision(DiffusionRequest $drequest,
$revision) {
$callsign = $drequest->getCallsign();
$name = 'r'.$callsign.$revision;
return phutil_render_tag(
'a',
array(
'href' => '/'.$name,
),
$name
);
}
private static function renderBrowse(
DiffusionRequest $drequest,
$path,
$name = null,
$rev = null,
$line = null,
$view = null,
$title = null) {
$callsign = $drequest->getCallsign();
if ($name === null) {
$name = $path;
}
$at = null;
if ($rev) {
$at = ';'.$rev;
}
if ($view) {
$view = '?view='.$view;
}
if ($line) {
$line = '$'.$line;
}
return phutil_render_tag(
'a',
array(
'href' => "/diffusion/{$callsign}/browse/{$path}{$at}{$line}{$view}",
'title' => $title,
),
$name
);
}
private function loadFileForData($path, $data) {
return PhabricatorFile::buildFromFileDataOrHash(
$data,
array(
'name' => basename($path),
));
}
private function buildRawResponse($path, $data) {
$file = $this->loadFileForData($path, $data);
return id(new AphrontRedirectResponse())->setURI($file->getBestURI());
}
private function buildImageCorpus($file_uri) {
$properties = new PhabricatorPropertyListView();
$properties->addProperty(
pht('Image'),
phutil_render_tag(
'img',
array(
'src' => $file_uri,
)));
$actions = id(new PhabricatorActionListView())
->setUser($this->getRequest()->getUser())
->addAction($this->createEditAction());
return array($actions, $properties);
}
private function buildBinaryCorpus($file_uri, $data) {
$properties = new PhabricatorPropertyListView();
$properties->addTextContent(
pht('This is a binary file. It is %d bytes in length.',
number_format(strlen($data)))
);
$actions = id(new PhabricatorActionListView())
->setUser($this->getRequest()->getUser())
->addAction($this->createEditAction())
->addAction(id(new PhabricatorActionView())
->setName(pht('Download Binary File...'))
->setIcon('download')
->setHref($file_uri));
return array($actions, $properties);
}
private function buildBeforeResponse($before) {
$request = $this->getRequest();
$drequest = $this->getDiffusionRequest();
// NOTE: We need to get the grandparent so we can capture filename changes
// in the parent.
$parent = $this->loadParentRevisionOf($before);
$old_filename = null;
$was_created = false;
if ($parent) {
$grandparent = $this->loadParentRevisionOf(
$parent->getCommitIdentifier());
if ($grandparent) {
$rename_query = new DiffusionRenameHistoryQuery();
$rename_query->setRequest($drequest);
$rename_query->setOldCommit($grandparent->getCommitIdentifier());
$old_filename = $rename_query->loadOldFilename();
$was_created = $rename_query->getWasCreated();
}
}
$follow = null;
if ($was_created) {
// If the file was created in history, that means older commits won't
// have it. Since we know it existed at 'before', it must have been
// created then; jump there.
$target_commit = $before;
$follow = 'created';
} else if ($parent) {
// If we found a parent, jump to it. This is the normal case.
$target_commit = $parent->getCommitIdentifier();
} else {
// If there's no parent, this was probably created in the initial commit?
// And the "was_created" check will fail because we can't identify the
// grandparent. Keep the user at 'before'.
$target_commit = $before;
$follow = 'first';
}
$path = $drequest->getPath();
$renamed = null;
if ($old_filename !== null &&
$old_filename !== '/'.$path) {
$renamed = $path;
$path = $old_filename;
}
$line = null;
// If there's a follow error, drop the line so the user sees the message.
if (!$follow) {
$line = $this->getBeforeLineNumber($target_commit);
}
$before_uri = $drequest->generateURI(
array(
'action' => 'browse',
'commit' => $target_commit,
'line' => $line,
'path' => $path,
));
$before_uri->setQueryParams($request->getRequestURI()->getQueryParams());
$before_uri = $before_uri->alter('before', null);
$before_uri = $before_uri->alter('renamed', $renamed);
$before_uri = $before_uri->alter('follow', $follow);
return id(new AphrontRedirectResponse())->setURI($before_uri);
}
private function getBeforeLineNumber($target_commit) {
$drequest = $this->getDiffusionRequest();
$line = $drequest->getLine();
if (!$line) {
return null;
}
$diff_query = DiffusionRawDiffQuery::newFromDiffusionRequest($drequest);
$diff_query->setAgainstCommit($target_commit);
try {
$raw_diff = $diff_query->loadRawDiff();
$old_line = 0;
$new_line = 0;
foreach (explode("\n", $raw_diff) as $text) {
if ($text[0] == '-' || $text[0] == ' ') {
$old_line++;
}
if ($text[0] == '+' || $text[0] == ' ') {
$new_line++;
}
if ($new_line == $line) {
return $old_line;
}
}
// We didn't find the target line.
return $line;
} catch (Exception $ex) {
return $line;
}
}
private function loadParentRevisionOf($commit) {
$drequest = $this->getDiffusionRequest();
$before_req = DiffusionRequest::newFromDictionary(
array(
'repository' => $drequest->getRepository(),
'commit' => $commit,
));
$query = DiffusionCommitParentsQuery::newFromDiffusionRequest($before_req);
$parents = $query->loadParents();
return head($parents);
}
}
diff --git a/src/applications/diffusion/controller/DiffusionLintController.php b/src/applications/diffusion/controller/DiffusionLintController.php
index 9ace062608..81f6d50459 100644
--- a/src/applications/diffusion/controller/DiffusionLintController.php
+++ b/src/applications/diffusion/controller/DiffusionLintController.php
@@ -1,121 +1,123 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
final class DiffusionLintController extends DiffusionController {
public function processRequest() {
$drequest = $this->getDiffusionRequest();
- if ($this->getRequest()->getStr('lint')) {
+ if ($this->getRequest()->getStr('lint') !== null) {
$controller = new DiffusionLintDetailsController($this->getRequest());
$controller->setDiffusionRequest($drequest);
return $this->delegateToController($controller);
}
$codes = $this->loadLintCodes();
$codes = array_reverse(isort($codes, 'n'));
$rows = array();
foreach ($codes as $code) {
$rows[] = array(
hsprintf(
'<a href="%s">%s</a>',
$drequest->generateURI(array(
'action' => 'lint',
'lint' => $code['code'],
)),
$code['n']),
hsprintf(
'<a href="%s">%s</a>',
$drequest->generateURI(array(
'action' => 'browse',
'lint' => $code['code'],
)),
$code['files']),
phutil_escape_html(ArcanistLintSeverity::getStringForSeverity(
$code['maxSeverity'])),
phutil_escape_html($code['code']),
phutil_escape_html($code['maxName']),
phutil_escape_html($code['maxDescription']),
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(array(
'Problems',
'Files',
'Severity',
'Code',
'Name',
'Example',
))
- ->setColumnClasses(array(
- 'n',
- 'n',
- '',
- 'pri',
- '',
- '',
- ));
+ ->setColumnClasses(array('n', 'n', '', 'pri', '', ''));
$content = array();
$content[] = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'lint',
));
+ $link = hsprintf(
+ '<a href="%s">%s</a>',
+ $drequest->generateURI(array(
+ 'action' => 'lint',
+ 'lint' => '',
+ )),
+ pht('Switch to List View'));
+
$content[] = id(new AphrontPanelView())
->setHeader(pht('%d Lint Message(s)', array_sum(ipull($codes, 'n'))))
+ ->setCaption($link)
->appendChild($table);
$nav = $this->buildSideNav('lint', false);
$nav->appendChild($content);
return $this->buildStandardPageResponse(
$nav,
array('title' => array(
'Lint',
$drequest->getRepository()->getCallsign(),
)));
}
private function loadLintCodes() {
$drequest = $this->getDiffusionRequest();
$branch = $drequest->loadBranch();
if (!$branch) {
return array();
}
$conn = $branch->establishConnection('r');
$where = '';
if ($drequest->getPath() != '') {
$is_dir = (substr($drequest->getPath(), -1) == '/');
$where = qsprintf(
$conn,
'AND path '.($is_dir ? 'LIKE %>' : '= %s'),
'/'.$drequest->getPath());
}
return queryfx_all(
$conn,
'SELECT
code,
MAX(severity) AS maxSeverity,
MAX(name) AS maxName,
MAX(description) AS maxDescription,
COUNT(DISTINCT path) AS files,
COUNT(*) AS n
FROM %T
WHERE branchID = %d
%Q
GROUP BY code',
PhabricatorRepository::TABLE_LINTMESSAGE,
$branch->getID(),
$where);
}
}
diff --git a/src/applications/diffusion/controller/DiffusionLintDetailsController.php b/src/applications/diffusion/controller/DiffusionLintDetailsController.php
index 8404e5ad43..c8cc969016 100644
--- a/src/applications/diffusion/controller/DiffusionLintDetailsController.php
+++ b/src/applications/diffusion/controller/DiffusionLintDetailsController.php
@@ -1,131 +1,142 @@
<?php
// Copyright 2004-present Facebook. All Rights Reserved.
final class DiffusionLintDetailsController extends DiffusionController {
public function processRequest() {
$limit = 500;
$offset = $this->getRequest()->getInt('offset', 0);
$drequest = $this->getDiffusionRequest();
- $messages = $this->loadLintMessages($limit, $offset);
+ $branch = $drequest->loadBranch();
+ $messages = $this->loadLintMessages($branch, $limit, $offset);
$is_dir = (substr('/'.$drequest->getPath(), -1) == '/');
$rows = array();
foreach ($messages as $message) {
$path = hsprintf(
'<a href="%s">%s</a>',
$drequest->generateURI(array(
'action' => 'lint',
'path' => $message['path'],
)),
substr($message['path'], strlen($drequest->getPath()) + 1));
$line = hsprintf(
'<a href="%s">%s</a>',
$drequest->generateURI(array(
'action' => 'browse',
'path' => $message['path'],
'line' => $message['line'],
+ 'commit' => $branch->getLintCommit(),
)),
$message['line']);
$rows[] = array(
$path,
$line,
phutil_escape_html(ArcanistLintSeverity::getStringForSeverity(
$message['severity'])),
- phutil_escape_html($message['code']),
phutil_escape_html($message['name']),
phutil_escape_html($message['description']),
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(array(
'Path',
'Line',
'Severity',
- 'Code',
'Name',
- 'Example',
- ))
- ->setColumnClasses(array(
- '',
- 'n',
- '',
- 'pri',
- '',
- '',
+ 'Description',
))
- ->setColumnVisibility(array(
- $is_dir,
- ));
+ ->setColumnClasses(array('', 'n', '', '', ''))
+ ->setColumnVisibility(array($is_dir));
$content = array();
$content[] = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'lint',
));
$pager = id(new AphrontPagerView())
->setPageSize($limit)
->setOffset($offset)
->setHasMorePages(count($messages) >= $limit)
->setURI($this->getRequest()->getRequestURI(), 'offset');
+ $lint = $drequest->getLint();
+ $link = hsprintf(
+ '<a href="%s">%s</a>',
+ $drequest->generateURI(array(
+ 'action' => 'lint',
+ 'lint' => null,
+ )),
+ pht('Switch to Grouped View'));
+
$content[] = id(new AphrontPanelView())
- ->setHeader(pht('%d Lint Message(s)', count($messages)))
+ ->setHeader(
+ ($lint != '' ? phutil_escape_html($lint)." \xC2\xB7 " : '').
+ pht('%d Lint Message(s)', count($messages)))
+ ->setCaption($link)
->appendChild($table)
->appendChild($pager);
$nav = $this->buildSideNav('lint', false);
$nav->appendChild($content);
return $this->buildStandardPageResponse(
$nav,
array('title' => array(
'Lint',
$drequest->getRepository()->getCallsign(),
)));
}
- private function loadLintMessages($limit, $offset) {
+ private function loadLintMessages(
+ PhabricatorRepositoryBranch $branch,
+ $limit,
+ $offset) {
+
$drequest = $this->getDiffusionRequest();
- $branch = $drequest->loadBranch();
if (!$branch) {
return array();
}
$conn = $branch->establishConnection('r');
- $where = '';
+ $where = array();
if ($drequest->getPath() != '') {
$is_dir = (substr($drequest->getPath(), -1) == '/');
- $where = qsprintf(
+ $where[] = qsprintf(
$conn,
- 'AND path '.($is_dir ? 'LIKE %>' : '= %s'),
+ 'path '.($is_dir ? 'LIKE %>' : '= %s'),
'/'.$drequest->getPath());
}
+ if ($drequest->getLint() != '') {
+ $where[] = qsprintf(
+ $conn,
+ 'code = %s',
+ $drequest->getLint());
+ }
+
return queryfx_all(
$conn,
'SELECT *
FROM %T
WHERE branchID = %d
- AND code = %s
- %Q
+ AND %Q
ORDER BY path, code, line
LIMIT %d OFFSET %d',
PhabricatorRepository::TABLE_LINTMESSAGE,
$branch->getID(),
- $drequest->getLint(),
- $where,
+ implode(' AND ', $where),
$limit,
$offset);
}
}
diff --git a/src/applications/diffusion/request/DiffusionRequest.php b/src/applications/diffusion/request/DiffusionRequest.php
index 59817092d2..94610f3790 100644
--- a/src/applications/diffusion/request/DiffusionRequest.php
+++ b/src/applications/diffusion/request/DiffusionRequest.php
@@ -1,559 +1,559 @@
<?php
/**
* Contains logic to parse Diffusion requests, which have a complicated URI
* structure.
*
*
* @task new Creating Requests
* @task uri Managing Diffusion URIs
*
* @group diffusion
*/
abstract class DiffusionRequest {
protected $callsign;
protected $path;
protected $line;
protected $symbolicCommit;
protected $commit;
protected $branch;
protected $commitType = 'commit';
protected $tagContent;
protected $lint;
protected $repository;
protected $repositoryCommit;
protected $repositoryCommitData;
protected $stableCommitName;
protected $arcanistProjects;
abstract protected function getSupportsBranches();
abstract protected function didInitialize();
/* -( Creating Requests )-------------------------------------------------- */
/**
* Create a new synthetic request from a parameter dictionary. If you need
* a @{class:DiffusionRequest} object in order to issue a DiffusionQuery, you
* can use this method to build one.
*
* Parameters are:
*
* - `callsign` Repository callsign. Provide this or `repository`.
* - `repository` Repository object. Provide this or `callsign`.
* - `branch` Optional, branch name.
* - `path` Optional, file path.
* - `commit` Optional, commit identifier.
* - `line` Optional, line range.
*
* @param map See documentation.
* @return DiffusionRequest New request object.
* @task new
*/
final public static function newFromDictionary(array $data) {
if (isset($data['repository']) && isset($data['callsign'])) {
throw new Exception(
"Specify 'repository' or 'callsign', but not both.");
} else if (!isset($data['repository']) && !isset($data['callsign'])) {
throw new Exception(
"One of 'repository' and 'callsign' is required.");
}
if (isset($data['repository'])) {
$object = self::newFromRepository($data['repository']);
} else {
$object = self::newFromCallsign($data['callsign']);
}
$object->initializeFromDictionary($data);
return $object;
}
/**
* Create a new request from an Aphront request dictionary. This is an
* internal method that you generally should not call directly; instead,
* call @{method:newFromDictionary}.
*
* @param map Map of Aphront request data.
* @return DiffusionRequest New request object.
* @task new
*/
final public static function newFromAphrontRequestDictionary(
array $data,
AphrontRequest $request) {
$callsign = phutil_unescape_uri_path_component(idx($data, 'callsign'));
$object = self::newFromCallsign($callsign);
$use_branches = $object->getSupportsBranches();
$parsed = self::parseRequestBlob(idx($data, 'dblob'), $use_branches);
$object->initializeFromDictionary($parsed);
$object->lint = $request->getStr('lint');
return $object;
}
/**
* Internal.
*
* @task new
*/
final private function __construct() {
// <private>
}
/**
* Internal. Use @{method:newFromDictionary}, not this method.
*
* @param string Repository callsign.
* @return DiffusionRequest New request object.
* @task new
*/
final private static function newFromCallsign($callsign) {
$repository = id(new PhabricatorRepository())->loadOneWhere(
'callsign = %s',
$callsign);
if (!$repository) {
throw new Exception("No such repository '{$callsign}'.");
}
return self::newFromRepository($repository);
}
/**
* Internal. Use @{method:newFromDictionary}, not this method.
*
* @param PhabricatorRepository Repository object.
* @return DiffusionRequest New request object.
* @task new
*/
final private static function newFromRepository(
PhabricatorRepository $repository) {
$map = array(
PhabricatorRepositoryType::REPOSITORY_TYPE_GIT => 'DiffusionGitRequest',
PhabricatorRepositoryType::REPOSITORY_TYPE_SVN => 'DiffusionSvnRequest',
PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL =>
'DiffusionMercurialRequest',
);
$class = idx($map, $repository->getVersionControlSystem());
if (!$class) {
throw new Exception("Unknown version control system!");
}
$object = new $class();
$object->repository = $repository;
$object->callsign = $repository->getCallsign();
return $object;
}
/**
* Internal. Use @{method:newFromDictionary}, not this method.
*
* @param map Map of parsed data.
* @return void
* @task new
*/
final private function initializeFromDictionary(array $data) {
$this->path = idx($data, 'path');
$this->symbolicCommit = idx($data, 'commit');
$this->commit = idx($data, 'commit');
$this->line = idx($data, 'line');
if ($this->getSupportsBranches()) {
$this->branch = idx($data, 'branch');
}
$this->didInitialize();
}
public function getRepository() {
return $this->repository;
}
public function getCallsign() {
return $this->callsign;
}
public function setPath($path) {
$this->path = $path;
return $this;
}
public function getPath() {
return $this->path;
}
public function getLine() {
return $this->line;
}
public function getCommit() {
return $this->commit;
}
public function getSymbolicCommit() {
return $this->symbolicCommit;
}
public function getBranch() {
return $this->branch;
}
public function getLint() {
return $this->lint;
}
protected function getArcanistBranch() {
return $this->getBranch();
}
public function loadBranch() {
return id(new PhabricatorRepositoryBranch())->loadOneWhere(
'repositoryID = %d AND name = %s',
$this->getRepository()->getID(),
$this->getArcanistBranch());
}
public function getTagContent() {
return $this->tagContent;
}
public function loadCommit() {
if (empty($this->repositoryCommit)) {
$repository = $this->getRepository();
$commit = id(new PhabricatorRepositoryCommit())->loadOneWhere(
'repositoryID = %d AND commitIdentifier = %s',
$repository->getID(),
$this->getCommit());
$this->repositoryCommit = $commit;
}
return $this->repositoryCommit;
}
public function loadArcanistProjects() {
if (empty($this->arcanistProjects)) {
$projects = id(new PhabricatorRepositoryArcanistProject())->loadAllWhere(
'repositoryID = %d',
$this->getRepository()->getID());
$this->arcanistProjects = $projects;
}
return $this->arcanistProjects;
}
public function loadCommitData() {
if (empty($this->repositoryCommitData)) {
$commit = $this->loadCommit();
$data = id(new PhabricatorRepositoryCommitData())->loadOneWhere(
'commitID = %d',
$commit->getID());
if (!$data) {
$data = new PhabricatorRepositoryCommitData();
$data->setCommitMessage(
'(This commit has not been fully parsed yet.)');
}
$this->repositoryCommitData = $data;
}
return $this->repositoryCommitData;
}
/**
* Retrieve a stable, permanent commit name. This returns a non-symbolic
* identifier for the current commit: e.g., a specific commit hash in git
* (NOT a symbolic name like "origin/master") or a specific revision number
* in SVN (NOT a symbolic name like "HEAD").
*
* @return string Stable commit name, like a git hash or SVN revision. Not
* a symbolic commit reference.
*/
public function getStableCommitName() {
return $this->stableCommitName;
}
final public function getRawCommit() {
return $this->commit;
}
public function setCommit($commit) {
$this->commit = $commit;
return $this;
}
/* -( Managing Diffusion URIs )-------------------------------------------- */
/**
* Generate a Diffusion URI using this request to provide defaults. See
* @{method:generateDiffusionURI} for details. This method is the same, but
* preserves the request parameters if they are not overridden.
*
* @param map See @{method:generateDiffusionURI}.
* @return PhutilURI Generated URI.
* @task uri
*/
public function generateURI(array $params) {
if (empty($params['stable'])) {
$default_commit = $this->getRawCommit();
} else {
$default_commit = $this->getStableCommitName();
}
$defaults = array(
'callsign' => $this->getCallsign(),
'path' => $this->getPath(),
'branch' => $this->getBranch(),
'commit' => $default_commit,
- 'lint' => $this->getLint(),
+ 'lint' => idx($params, 'lint', $this->getLint()),
);
foreach ($defaults as $key => $val) {
if (!isset($params[$key])) { // Overwrite NULL.
$params[$key] = $val;
}
}
return self::generateDiffusionURI($params);
}
/**
* Generate a Diffusion URI from a parameter map. Applies the correct encoding
* and formatting to the URI. Parameters are:
*
* - `action` One of `history`, `browse`, `change`, `lastmodified`,
* `branch` or `revision-ref`. The action specified by the URI.
* - `callsign` Repository callsign.
* - `branch` Optional if action is not `branch`, branch name.
* - `path` Optional, path to file.
* - `commit` Optional, commit identifier.
* - `line` Optional, line range.
* - `lint` Optional, lint code.
* - `params` Optional, query parameters.
*
* The function generates the specified URI and returns it.
*
* @param map See documentation.
* @return PhutilURI Generated URI.
* @task uri
*/
public static function generateDiffusionURI(array $params) {
$action = idx($params, 'action');
$callsign = idx($params, 'callsign');
$path = idx($params, 'path');
$branch = idx($params, 'branch');
$commit = idx($params, 'commit');
$line = idx($params, 'line');
if (strlen($callsign)) {
$callsign = phutil_escape_uri_path_component($callsign).'/';
}
if (strlen($branch)) {
$branch = phutil_escape_uri_path_component($branch).'/';
}
if (strlen($path)) {
$path = ltrim($path, '/');
$path = str_replace(array(';', '$'), array(';;', '$$'), $path);
$path = phutil_escape_uri($path);
}
$path = "{$branch}{$path}";
if (strlen($commit)) {
$commit = str_replace('$', '$$', $commit);
$commit = ';'.phutil_escape_uri($commit);
}
if (strlen($line)) {
$line = '$'.phutil_escape_uri($line);
}
$req_callsign = false;
$req_branch = false;
$req_commit = false;
switch ($action) {
case 'history':
case 'browse':
case 'change':
case 'lastmodified':
case 'tags':
case 'branches':
case 'lint':
$req_callsign = true;
break;
case 'branch':
$req_callsign = true;
$req_branch = true;
break;
case 'commit':
$req_callsign = true;
$req_commit = true;
break;
}
if ($req_callsign && !strlen($callsign)) {
throw new Exception(
"Diffusion URI action '{$action}' requires callsign!");
}
if ($req_branch && !strlen($branch)) {
throw new Exception(
"Diffusion URI action '{$action}' requires branch!");
}
if ($req_commit && !strlen($commit)) {
throw new Exception(
"Diffusion URI action '{$action}' requires commit!");
}
switch ($action) {
case 'change':
case 'history':
case 'browse':
case 'lastmodified':
case 'tags':
case 'branches':
case 'lint':
$uri = "/diffusion/{$callsign}{$action}/{$path}{$commit}{$line}";
break;
case 'branch':
$uri = "/diffusion/{$callsign}repository/{$path}";
break;
case 'external':
$commit = ltrim($commit, ';');
$uri = "/diffusion/external/{$commit}/";
break;
case 'rendering-ref':
// This isn't a real URI per se, it's passed as a query parameter to
// the ajax changeset stuff but then we parse it back out as though
// it came from a URI.
$uri = rawurldecode("{$path}{$commit}");
break;
case 'commit':
$commit = ltrim($commit, ';');
$callsign = rtrim($callsign, '/');
$uri = "/r{$callsign}{$commit}";
break;
default:
throw new Exception("Unknown Diffusion URI action '{$action}'!");
}
if ($action == 'rendering-ref') {
return $uri;
}
$uri = new PhutilURI($uri);
if (isset($params['lint'])) {
$params['params'] = idx($params, 'params', array()) + array(
'lint' => $params['lint'],
);
}
if (idx($params, 'params')) {
$uri->setQueryParams($params['params']);
}
return $uri;
}
/**
* Internal. Public only for unit tests.
*
* Parse the request URI into components.
*
* @param string URI blob.
* @param bool True if this VCS supports branches.
* @return map Parsed URI.
*
* @task uri
*/
public static function parseRequestBlob($blob, $supports_branches) {
$result = array(
'branch' => null,
'path' => null,
'commit' => null,
'line' => null,
);
$matches = null;
if ($supports_branches) {
// Consume the front part of the URI, up to the first "/". This is the
// path-component encoded branch name.
if (preg_match('@^([^/]+)/@', $blob, $matches)) {
$result['branch'] = phutil_unescape_uri_path_component($matches[1]);
$blob = substr($blob, strlen($matches[1]) + 1);
}
}
// Consume the back part of the URI, up to the first "$". Use a negative
// lookbehind to prevent matching '$$'. We double the '$' symbol when
// encoding so that files with names like "money/$100" will survive.
$pattern = '@(?:(?:^|[^$])(?:[$][$])*)[$]([\d-,]+)$@';
if (preg_match($pattern, $blob, $matches)) {
$result['line'] = $matches[1];
$blob = substr($blob, 0, -(strlen($matches[1]) + 1));
}
// We've consumed the line number if it exists, so unescape "$" in the
// rest of the string.
$blob = str_replace('$$', '$', $blob);
// Consume the commit name, stopping on ';;'. We allow any character to
// appear in commits names, as they can sometimes be symbolic names (like
// tag names or refs).
if (preg_match('@(?:(?:^|[^;])(?:;;)*);([^;].*)$@', $blob, $matches)) {
$result['commit'] = $matches[1];
$blob = substr($blob, 0, -(strlen($matches[1]) + 1));
}
// We've consumed the commit if it exists, so unescape ";" in the rest
// of the string.
$blob = str_replace(';;', ';', $blob);
if (strlen($blob)) {
$result['path'] = $blob;
}
$parts = explode('/', $result['path']);
foreach ($parts as $part) {
// Prevent any hyjinx since we're ultimately shipping this to the
// filesystem under a lot of workflows.
if ($part == '..') {
throw new Exception("Invalid path URI.");
}
}
return $result;
}
protected function raiseCloneException() {
$host = php_uname('n');
$callsign = $this->getRepository()->getCallsign();
throw new DiffusionSetupException(
"The working copy for this repository ('{$callsign}') hasn't been ".
"cloned yet on this machine ('{$host}'). Make sure you've started the ".
"Phabricator daemons. If this problem persists for longer than a clone ".
"should take, check the daemon logs (in the Daemon Console) to see if ".
"there were errors cloning the repository. Consult the 'Diffusion User ".
"Guide' in the documentation for help setting up repositories.");
}
}
diff --git a/src/applications/diffusion/view/DiffusionBrowseTableView.php b/src/applications/diffusion/view/DiffusionBrowseTableView.php
index 17a8924f59..a5ab00bbfd 100644
--- a/src/applications/diffusion/view/DiffusionBrowseTableView.php
+++ b/src/applications/diffusion/view/DiffusionBrowseTableView.php
@@ -1,295 +1,295 @@
<?php
final class DiffusionBrowseTableView extends DiffusionView {
private $paths;
private $handles = array();
private $user;
public function setPaths(array $paths) {
assert_instances_of($paths, 'DiffusionRepositoryPath');
$this->paths = $paths;
return $this;
}
public function setHandles(array $handles) {
assert_instances_of($handles, 'PhabricatorObjectHandle');
$this->handles = $handles;
return $this;
}
public function setUser(PhabricatorUser $user) {
$this->user = $user;
return $this;
}
public static function renderLastModifiedColumns(
DiffusionRequest $drequest,
array $handles,
PhabricatorRepositoryCommit $commit = null,
PhabricatorRepositoryCommitData $data = null) {
assert_instances_of($handles, 'PhabricatorObjectHandle');
if ($commit) {
$epoch = $commit->getEpoch();
$modified = DiffusionView::linkCommit(
$drequest->getRepository(),
$commit->getCommitIdentifier());
$date = date('M j, Y', $epoch);
$time = date('g:i A', $epoch);
} else {
$modified = '';
$date = '';
$time = '';
}
if ($data) {
$author_phid = $data->getCommitDetail('authorPHID');
if ($author_phid && isset($handles[$author_phid])) {
$author = $handles[$author_phid]->renderLink();
} else {
$author = self::renderName($data->getAuthorName());
}
$committer = $data->getCommitDetail('committer');
if ($committer) {
$committer_phid = $data->getCommitDetail('committerPHID');
if ($committer_phid && isset($handles[$committer_phid])) {
$committer = $handles[$committer_phid]->renderLink();
} else {
$committer = self::renderName($committer);
}
if ($author != $committer) {
$author .= '/'.$committer;
}
}
$details = AphrontTableView::renderSingleDisplayLine(
phutil_escape_html($data->getSummary()));
} else {
$author = '';
$details = '';
}
$return = array(
'commit' => $modified,
'date' => $date,
'time' => $time,
'author' => $author,
'details' => $details,
);
$lint = self::loadLintMessagesCount($drequest);
if ($lint !== null) {
$return['lint'] = hsprintf(
'<a href="%s">%s</a>',
$drequest->generateURI(array(
'action' => 'lint',
- 'lint' => '',
+ 'lint' => null,
)),
number_format($lint));
}
return $return;
}
private static function loadLintMessagesCount(DiffusionRequest $drequest) {
$branch = $drequest->loadBranch();
if (!$branch) {
return null;
}
$conn = $drequest->getRepository()->establishConnection('r');
$where = '';
if ($drequest->getLint()) {
$where = qsprintf(
$conn,
'AND code = %s',
$drequest->getLint());
}
$like = (substr($drequest->getPath(), -1) == '/' ? 'LIKE %>' : '= %s');
return head(queryfx_one(
$conn,
'SELECT COUNT(*) FROM %T WHERE branchID = %d %Q AND path '.$like,
PhabricatorRepository::TABLE_LINTMESSAGE,
$branch->getID(),
$where,
'/'.$drequest->getPath()));
}
public function render() {
$request = $this->getDiffusionRequest();
$repository = $request->getRepository();
$base_path = trim($request->getPath(), '/');
if ($base_path) {
$base_path = $base_path.'/';
}
$need_pull = array();
$rows = array();
$show_edit = false;
foreach ($this->paths as $path) {
$dir_slash = null;
$file_type = $path->getFileType();
if ($file_type == DifferentialChangeType::FILE_DIRECTORY) {
$browse_text = $path->getPath().'/';
$dir_slash = '/';
$browse_link = '<strong>'.$this->linkBrowse(
$base_path.$path->getPath().$dir_slash,
array(
'html' => $this->renderPathIcon(
'dir',
$browse_text),
)).'</strong>';
} else if ($file_type == DifferentialChangeType::FILE_SUBMODULE) {
$browse_text = $path->getPath().'/';
$browse_link =
'<strong>'.
$this->linkExternal(
$path->getHash(),
$path->getExternalURI(),
$this->renderPathIcon(
'ext',
$browse_text)).
'</strong>';
} else {
if ($file_type == DifferentialChangeType::FILE_SYMLINK) {
$type = 'link';
} else {
$type = 'file';
}
$browse_text = $path->getPath();
$browse_link = $this->linkBrowse(
$base_path.$path->getPath(),
array(
'html' => $this->renderPathIcon($type, $browse_text),
));
}
$commit = $path->getLastModifiedCommit();
if ($commit) {
$drequest = clone $request;
- $drequest->setPath($path->getPath().$dir_slash);
+ $drequest->setPath($request->getPath().$path->getPath().$dir_slash);
$dict = self::renderLastModifiedColumns(
$drequest,
$this->handles,
$commit,
$path->getLastCommitData());
} else {
$dict = array(
'lint' => celerity_generate_unique_node_id(),
'commit' => celerity_generate_unique_node_id(),
'date' => celerity_generate_unique_node_id(),
'time' => celerity_generate_unique_node_id(),
'author' => celerity_generate_unique_node_id(),
'details' => celerity_generate_unique_node_id(),
);
$uri = (string)$request->generateURI(
array(
'action' => 'lastmodified',
'path' => $base_path.$path->getPath().$dir_slash,
));
$need_pull[$uri] = $dict;
foreach ($dict as $k => $uniq) {
$dict[$k] = '<span id="'.$uniq.'"></span>';
}
}
$editor_button = '';
if ($this->user) {
$editor_link = $this->user->loadEditorLink(
$base_path.$path->getPath(),
1,
$request->getRepository()->getCallsign());
if ($editor_link) {
$show_edit = true;
$editor_button = phutil_render_tag(
'a',
array(
'href' => $editor_link,
),
'Edit');
}
}
$rows[] = array(
$this->linkHistory($base_path.$path->getPath().$dir_slash),
$editor_button,
$browse_link,
$dict['lint'],
$dict['commit'],
$dict['date'],
$dict['time'],
$dict['author'],
$dict['details'],
);
}
if ($need_pull) {
Javelin::initBehavior('diffusion-pull-lastmodified', $need_pull);
}
$branch = $this->getDiffusionRequest()->loadBranch();
$show_lint = ($branch && $branch->getLintCommit());
$lint = $request->getLint();
$view = new AphrontTableView($rows);
$view->setHeaders(
array(
'History',
'Edit',
'Path',
($lint ? phutil_escape_html($lint) : 'Lint'),
'Modified',
'Date',
'Time',
'Author/Committer',
'Details',
));
$view->setColumnClasses(
array(
'',
'',
'',
'n',
'',
'',
'right',
'',
'wide',
));
$view->setColumnVisibility(
array(
true,
$show_edit,
true,
$show_lint,
true,
true,
true,
true,
true,
));
return $view->render();
}
private function renderPathIcon($type, $text) {
require_celerity_resource('diffusion-icons-css');
return phutil_render_tag(
'span',
array(
'class' => 'diffusion-path-icon diffusion-path-icon-'.$type,
),
phutil_escape_html($text));
}
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Jul 28, 10:48 AM (1 w, 1 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
186714
Default Alt Text
(62 KB)

Event Timeline