2011-03-08 18:54:55 +01:00
|
|
|
<?php
|
|
|
|
|
2012-03-10 00:46:25 +01:00
|
|
|
final class DiffusionBrowseFileController extends DiffusionController {
|
2011-03-08 18:54:55 +01:00
|
|
|
|
2012-03-20 03:52:24 +01:00
|
|
|
private $corpusType = 'text';
|
2011-04-02 00:34:45 +02:00
|
|
|
|
2012-11-07 07:46:23 +01:00
|
|
|
private $lintCommit;
|
|
|
|
private $lintMessages;
|
|
|
|
|
2011-03-08 18:54:55 +01:00
|
|
|
public function processRequest() {
|
2011-03-13 01:17:34 +01:00
|
|
|
|
2011-03-23 03:34:47 +01:00
|
|
|
$request = $this->getRequest();
|
Allow Diffusion to display PDF files
Summary:
When Diffusion encounters an image file, it displays it as an
image, but when it encounters a PDF file, it currently shows only some
gibberish. This fixes that.
Test Plan:
I tried it. Embedding a large PDF in a data URL is a little
bit slow, but it works.
Reviewers: tuomaspelkonen, epriestley, gc3, waltermundt, jungejason, nh
Reviewed By: epriestley
CC: aran, tuomaspelkonen, epriestley, jaapweel
Differential Revision: 915
2011-09-09 00:23:58 +02:00
|
|
|
$drequest = $this->getDiffusionRequest();
|
2012-04-08 02:24:35 +02:00
|
|
|
|
|
|
|
$before = $request->getStr('before');
|
|
|
|
if ($before) {
|
|
|
|
return $this->buildBeforeResponse($before);
|
|
|
|
}
|
|
|
|
|
Allow Diffusion to display PDF files
Summary:
When Diffusion encounters an image file, it displays it as an
image, but when it encounters a PDF file, it currently shows only some
gibberish. This fixes that.
Test Plan:
I tried it. Embedding a large PDF in a data URL is a little
bit slow, but it works.
Reviewers: tuomaspelkonen, epriestley, gc3, waltermundt, jungejason, nh
Reviewed By: epriestley
CC: aran, tuomaspelkonen, epriestley, jaapweel
Differential Revision: 915
2011-09-09 00:23:58 +02:00
|
|
|
$path = $drequest->getPath();
|
2012-07-18 02:13:03 +02:00
|
|
|
|
2011-03-23 03:34:47 +01:00
|
|
|
$selected = $request->getStr('view');
|
2012-07-18 02:13:03 +02:00
|
|
|
$preferences = $request->getUser()->loadPreferences();
|
2012-06-07 19:55:10 +02:00
|
|
|
if (!$selected) {
|
2012-07-18 02:13:03 +02:00
|
|
|
$selected = $preferences->getPreference(
|
|
|
|
PhabricatorUserPreferences::PREFERENCE_DIFFUSION_VIEW,
|
|
|
|
'highlighted');
|
|
|
|
} else if ($request->isFormPost() && $selected != 'raw') {
|
|
|
|
$preferences->setPreference(
|
|
|
|
PhabricatorUserPreferences::PREFERENCE_DIFFUSION_VIEW,
|
|
|
|
$selected);
|
|
|
|
$preferences->save();
|
2012-07-19 19:15:06 +02:00
|
|
|
|
|
|
|
return id(new AphrontRedirectResponse())
|
|
|
|
->setURI($request->getRequestURI()->alter('view', $selected));
|
2012-06-07 19:55:10 +02:00
|
|
|
}
|
2012-07-18 02:13:03 +02:00
|
|
|
|
2013-03-05 23:31:20 +01:00
|
|
|
$needs_blame = ($selected == 'plainblame');
|
|
|
|
if ($selected == 'blame' && $request->isAjax()) {
|
|
|
|
$needs_blame = true;
|
|
|
|
}
|
2012-04-08 02:24:35 +02:00
|
|
|
|
Allow Diffusion to display PDF files
Summary:
When Diffusion encounters an image file, it displays it as an
image, but when it encounters a PDF file, it currently shows only some
gibberish. This fixes that.
Test Plan:
I tried it. Embedding a large PDF in a data URL is a little
bit slow, but it works.
Reviewers: tuomaspelkonen, epriestley, gc3, waltermundt, jungejason, nh
Reviewed By: epriestley
CC: aran, tuomaspelkonen, epriestley, jaapweel
Differential Revision: 915
2011-09-09 00:23:58 +02:00
|
|
|
$file_query = DiffusionFileContentQuery::newFromDiffusionRequest(
|
|
|
|
$this->diffusionRequest);
|
2012-09-05 04:22:03 +02:00
|
|
|
$file_query->setViewer($request->getUser());
|
Allow Diffusion to display PDF files
Summary:
When Diffusion encounters an image file, it displays it as an
image, but when it encounters a PDF file, it currently shows only some
gibberish. This fixes that.
Test Plan:
I tried it. Embedding a large PDF in a data URL is a little
bit slow, but it works.
Reviewers: tuomaspelkonen, epriestley, gc3, waltermundt, jungejason, nh
Reviewed By: epriestley
CC: aran, tuomaspelkonen, epriestley, jaapweel
Differential Revision: 915
2011-09-09 00:23:58 +02:00
|
|
|
$file_query->setNeedsBlame($needs_blame);
|
|
|
|
$file_query->loadFileContent();
|
|
|
|
$data = $file_query->getRawData();
|
2011-03-22 07:57:32 +01:00
|
|
|
|
2012-03-20 03:52:24 +01:00
|
|
|
if ($selected === 'raw') {
|
|
|
|
return $this->buildRawResponse($path, $data);
|
2012-03-14 07:50:34 +01:00
|
|
|
}
|
|
|
|
|
2012-11-07 07:46:23 +01:00
|
|
|
$this->loadLintMessages();
|
|
|
|
|
2011-03-26 20:42:12 +01:00
|
|
|
// Build the content of the file.
|
Allow Diffusion to display PDF files
Summary:
When Diffusion encounters an image file, it displays it as an
image, but when it encounters a PDF file, it currently shows only some
gibberish. This fixes that.
Test Plan:
I tried it. Embedding a large PDF in a data URL is a little
bit slow, but it works.
Reviewers: tuomaspelkonen, epriestley, gc3, waltermundt, jungejason, nh
Reviewed By: epriestley
CC: aran, tuomaspelkonen, epriestley, jaapweel
Differential Revision: 915
2011-09-09 00:23:58 +02:00
|
|
|
$corpus = $this->buildCorpus(
|
|
|
|
$selected,
|
|
|
|
$file_query,
|
|
|
|
$needs_blame,
|
|
|
|
$drequest,
|
|
|
|
$path,
|
2012-03-20 03:52:24 +01:00
|
|
|
$data);
|
|
|
|
|
2013-03-05 23:31:20 +01:00
|
|
|
if ($request->isAjax()) {
|
|
|
|
return id(new AphrontAjaxResponse())->setContent($corpus);
|
|
|
|
}
|
|
|
|
|
2012-03-20 03:52:24 +01:00
|
|
|
require_celerity_resource('diffusion-source-css');
|
|
|
|
|
|
|
|
if ($this->corpusType == 'text') {
|
2012-07-18 02:13:03 +02:00
|
|
|
$view_select_panel = $this->renderViewSelectPanel($selected);
|
2012-03-20 03:52:24 +01:00
|
|
|
} else {
|
|
|
|
$view_select_panel = null;
|
|
|
|
}
|
2011-03-26 20:42:12 +01:00
|
|
|
|
|
|
|
// Render the page.
|
|
|
|
$content = array();
|
2012-04-24 03:16:38 +02:00
|
|
|
|
|
|
|
$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(
|
2013-02-07 01:53:49 +01:00
|
|
|
"File history passes through a rename from '".$drequest->getPath().
|
|
|
|
"' to '".$renamed."'.");
|
2012-04-24 03:16:38 +02:00
|
|
|
$content[] = $notice;
|
|
|
|
}
|
|
|
|
|
2011-03-26 20:42:12 +01:00
|
|
|
$content[] = $view_select_panel;
|
|
|
|
$content[] = $corpus;
|
2011-10-02 21:52:54 +02:00
|
|
|
$content[] = $this->buildOpenRevisions();
|
2011-03-26 20:42:12 +01:00
|
|
|
|
|
|
|
$nav = $this->buildSideNav('browse', true);
|
|
|
|
$nav->appendChild($content);
|
upgrade diffusion to use modern header UI and fix a few quirks
Summary:
upgrades are CrumbsView, HeaderView, PropertyListView, and ActionListView. I had to modify CrumbsView stuff a bit to handle the "advanced" diffusion crumbs.
Quirks fixed include making file tree view show up in diffusion, the page not have extra space when the file tree is hidden, links no longer breaking once you visit files (since without the change the files always got "/" appended and thus 404'd), and a differential quirk where it read "next step:" and that colon is a no no,
Test Plan: played around in diffusion and differential
Reviewers: epriestley
Reviewed By: epriestley
CC: aran, Korvin, chad
Maniphest Tasks: T2048, T2178
Differential Revision: https://secure.phabricator.com/D4169
2012-12-13 02:50:42 +01:00
|
|
|
$crumbs = $this->buildCrumbs(
|
|
|
|
array(
|
|
|
|
'branch' => true,
|
|
|
|
'path' => true,
|
|
|
|
'view' => 'browse',
|
|
|
|
));
|
|
|
|
$nav->setCrumbs($crumbs);
|
2011-03-26 20:42:12 +01:00
|
|
|
|
2011-04-19 06:21:08 +02:00
|
|
|
$basename = basename($this->getDiffusionRequest()->getPath());
|
|
|
|
|
upgrade diffusion to use modern header UI and fix a few quirks
Summary:
upgrades are CrumbsView, HeaderView, PropertyListView, and ActionListView. I had to modify CrumbsView stuff a bit to handle the "advanced" diffusion crumbs.
Quirks fixed include making file tree view show up in diffusion, the page not have extra space when the file tree is hidden, links no longer breaking once you visit files (since without the change the files always got "/" appended and thus 404'd), and a differential quirk where it read "next step:" and that colon is a no no,
Test Plan: played around in diffusion and differential
Reviewers: epriestley
Reviewed By: epriestley
CC: aran, Korvin, chad
Maniphest Tasks: T2048, T2178
Differential Revision: https://secure.phabricator.com/D4169
2012-12-13 02:50:42 +01:00
|
|
|
return $this->buildApplicationPage(
|
2011-03-26 20:42:12 +01:00
|
|
|
$nav,
|
|
|
|
array(
|
2011-04-19 06:21:08 +02:00
|
|
|
'title' => $basename,
|
2011-03-26 20:42:12 +01:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2012-11-07 07:46:23 +01:00
|
|
|
private function loadLintMessages() {
|
|
|
|
$drequest = $this->getDiffusionRequest();
|
|
|
|
$branch = $drequest->loadBranch();
|
|
|
|
|
|
|
|
if (!$branch || !$branch->getLintCommit()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-01-14 22:22:02 +01:00
|
|
|
$this->lintCommit = $branch->getLintCommit();
|
2012-11-07 07:46:23 +01:00
|
|
|
|
2012-11-09 00:14:44 +01:00
|
|
|
$conn = id(new PhabricatorRepository())->establishConnection('r');
|
|
|
|
|
|
|
|
$where = '';
|
|
|
|
if ($drequest->getLint()) {
|
|
|
|
$where = qsprintf(
|
|
|
|
$conn,
|
|
|
|
'AND code = %s',
|
|
|
|
$drequest->getLint());
|
|
|
|
}
|
|
|
|
|
2012-11-07 07:46:23 +01:00
|
|
|
$this->lintMessages = queryfx_all(
|
2012-11-09 00:14:44 +01:00
|
|
|
$conn,
|
|
|
|
'SELECT * FROM %T WHERE branchID = %d %Q AND path = %s',
|
2012-11-07 07:46:23 +01:00
|
|
|
PhabricatorRepository::TABLE_LINTMESSAGE,
|
|
|
|
$branch->getID(),
|
2012-11-09 00:14:44 +01:00
|
|
|
$where,
|
2012-11-07 07:46:23 +01:00
|
|
|
'/'.$drequest->getPath());
|
|
|
|
}
|
|
|
|
|
Allow Diffusion to display PDF files
Summary:
When Diffusion encounters an image file, it displays it as an
image, but when it encounters a PDF file, it currently shows only some
gibberish. This fixes that.
Test Plan:
I tried it. Embedding a large PDF in a data URL is a little
bit slow, but it works.
Reviewers: tuomaspelkonen, epriestley, gc3, waltermundt, jungejason, nh
Reviewed By: epriestley
CC: aran, tuomaspelkonen, epriestley, jaapweel
Differential Revision: 915
2011-09-09 00:23:58 +02:00
|
|
|
private function buildCorpus($selected,
|
2012-04-07 21:01:25 +02:00
|
|
|
DiffusionFileContentQuery $file_query,
|
Allow Diffusion to display PDF files
Summary:
When Diffusion encounters an image file, it displays it as an
image, but when it encounters a PDF file, it currently shows only some
gibberish. This fixes that.
Test Plan:
I tried it. Embedding a large PDF in a data URL is a little
bit slow, but it works.
Reviewers: tuomaspelkonen, epriestley, gc3, waltermundt, jungejason, nh
Reviewed By: epriestley
CC: aran, tuomaspelkonen, epriestley, jaapweel
Differential Revision: 915
2011-09-09 00:23:58 +02:00
|
|
|
$needs_blame,
|
2012-04-07 21:01:25 +02:00
|
|
|
DiffusionRequest $drequest,
|
Allow Diffusion to display PDF files
Summary:
When Diffusion encounters an image file, it displays it as an
image, but when it encounters a PDF file, it currently shows only some
gibberish. This fixes that.
Test Plan:
I tried it. Embedding a large PDF in a data URL is a little
bit slow, but it works.
Reviewers: tuomaspelkonen, epriestley, gc3, waltermundt, jungejason, nh
Reviewed By: epriestley
CC: aran, tuomaspelkonen, epriestley, jaapweel
Differential Revision: 915
2011-09-09 00:23:58 +02:00
|
|
|
$path,
|
|
|
|
$data) {
|
2011-04-01 22:42:00 +02:00
|
|
|
|
2012-03-20 03:52:24 +01:00
|
|
|
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);
|
|
|
|
}
|
Allow Diffusion to display PDF files
Summary:
When Diffusion encounters an image file, it displays it as an
image, but when it encounters a PDF file, it currently shows only some
gibberish. This fixes that.
Test Plan:
I tried it. Embedding a large PDF in a data URL is a little
bit slow, but it works.
Reviewers: tuomaspelkonen, epriestley, gc3, waltermundt, jungejason, nh
Reviewed By: epriestley
CC: aran, tuomaspelkonen, epriestley, jaapweel
Differential Revision: 915
2011-09-09 00:23:58 +02:00
|
|
|
}
|
|
|
|
|
2011-03-23 03:34:47 +01:00
|
|
|
switch ($selected) {
|
|
|
|
case 'plain':
|
|
|
|
$style =
|
|
|
|
"margin: 1em 2em; width: 90%; height: 80em; font-family: monospace";
|
2013-01-18 03:43:35 +01:00
|
|
|
$corpus = phutil_tag(
|
2011-03-23 03:34:47 +01:00
|
|
|
'textarea',
|
|
|
|
array(
|
|
|
|
'style' => $style,
|
|
|
|
),
|
2013-01-18 03:43:35 +01:00
|
|
|
$file_query->getRawData());
|
2011-04-01 03:28:24 +02:00
|
|
|
|
2011-03-23 03:34:47 +01:00
|
|
|
break;
|
|
|
|
|
2011-04-01 03:28:24 +02:00
|
|
|
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];
|
2013-03-05 01:22:30 +01:00
|
|
|
$author = $blame_dict[$rev]['author'];
|
2011-04-01 03:28:24 +02:00
|
|
|
$rows[] =
|
2011-06-07 01:08:49 +02:00
|
|
|
sprintf("%-10s %-20s %s", substr($rev, 0, 7), $author, $line);
|
2011-04-01 03:28:24 +02:00
|
|
|
}
|
|
|
|
|
2013-01-18 03:43:35 +01:00
|
|
|
$corpus = phutil_tag(
|
2011-04-01 03:28:24 +02:00
|
|
|
'textarea',
|
|
|
|
array(
|
|
|
|
'style' => $style,
|
|
|
|
),
|
2013-01-18 03:43:35 +01:00
|
|
|
implode("\n", $rows));
|
2011-04-01 03:28:24 +02:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
2011-03-23 03:34:47 +01:00
|
|
|
case 'highlighted':
|
2011-03-26 20:42:12 +01:00
|
|
|
case 'blame':
|
2011-03-23 03:34:47 +01:00
|
|
|
default:
|
|
|
|
require_celerity_resource('syntax-highlighting-css');
|
2011-03-08 18:54:55 +01:00
|
|
|
|
2011-04-01 03:28:24 +02:00
|
|
|
list($text_list, $rev_list, $blame_dict) = $file_query->getBlameData();
|
2011-03-26 20:42:12 +01:00
|
|
|
|
2011-07-06 21:12:17 +02:00
|
|
|
$text_list = implode("\n", $text_list);
|
|
|
|
$text_list = PhabricatorSyntaxHighlighter::highlightWithFilename(
|
|
|
|
$path,
|
|
|
|
$text_list);
|
|
|
|
$text_list = explode("\n", $text_list);
|
2011-03-23 03:34:47 +01:00
|
|
|
|
2011-04-01 03:28:24 +02:00
|
|
|
$rows = $this->buildDisplayRows($text_list, $rev_list, $blame_dict,
|
2011-04-02 00:34:45 +02:00
|
|
|
$needs_blame, $drequest, $file_query, $selected);
|
2011-03-23 03:34:47 +01:00
|
|
|
|
2013-03-05 23:31:20 +01:00
|
|
|
$corpus_table = javelin_tag(
|
|
|
|
'table',
|
|
|
|
array(
|
|
|
|
'class' => "diffusion-source remarkup-code PhabricatorMonospaced",
|
|
|
|
'sigil' => 'diffusion-source',
|
|
|
|
),
|
|
|
|
$rows);
|
|
|
|
|
|
|
|
if ($this->getRequest()->isAjax()) {
|
|
|
|
return $corpus_table;
|
|
|
|
}
|
|
|
|
|
2012-07-20 07:01:31 +02:00
|
|
|
$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()));
|
|
|
|
|
2013-02-02 02:46:57 +01:00
|
|
|
if (isset($langs[$lang])) {
|
2012-07-20 07:01:31 +02:00
|
|
|
Javelin::initBehavior(
|
|
|
|
'repository-crossreference',
|
|
|
|
array(
|
|
|
|
'container' => $id,
|
|
|
|
'lang' => $lang,
|
|
|
|
'projects' => $langs[$lang],
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2013-01-18 09:32:58 +01:00
|
|
|
$corpus = phutil_tag(
|
2011-03-23 03:34:47 +01:00
|
|
|
'div',
|
|
|
|
array(
|
2012-04-08 02:24:35 +02:00
|
|
|
'style' => 'padding: 0 2em;',
|
2012-07-20 07:01:31 +02:00
|
|
|
'id' => $id,
|
2011-03-23 03:34:47 +01:00
|
|
|
),
|
|
|
|
$corpus_table);
|
|
|
|
|
2013-03-05 23:31:20 +01:00
|
|
|
Javelin::initBehavior('load-blame', array('id' => $id));
|
|
|
|
|
2011-03-23 03:34:47 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-03-26 20:42:12 +01:00
|
|
|
return $corpus;
|
|
|
|
}
|
2011-03-13 01:17:34 +01:00
|
|
|
|
2012-07-18 02:13:03 +02:00
|
|
|
private function renderViewSelectPanel($selected) {
|
2012-10-03 19:58:56 +02:00
|
|
|
$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();
|
2012-11-07 07:46:23 +01:00
|
|
|
$base_uri = $this->getRequest()->getRequestURI();
|
2012-10-03 19:58:56 +02:00
|
|
|
|
|
|
|
$blame_on = ($selected == 'blame' || $selected == 'plainblame');
|
|
|
|
if ($blame_on) {
|
|
|
|
$blame_text = pht('Disable Blame');
|
|
|
|
} else {
|
|
|
|
$blame_text = pht('Enable Blame');
|
|
|
|
}
|
2012-03-20 03:52:24 +01:00
|
|
|
|
2012-10-03 19:58:56 +02:00
|
|
|
$blame_button = $this->createViewAction(
|
|
|
|
$blame_text,
|
2012-11-07 07:46:23 +01:00
|
|
|
$base_uri->alter('view', $toggle_blame[$selected]),
|
2012-10-03 19:58:56 +02:00
|
|
|
$user);
|
2012-03-20 03:52:24 +01:00
|
|
|
|
|
|
|
|
2012-10-03 19:58:56 +02:00
|
|
|
$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,
|
2012-11-07 07:46:23 +01:00
|
|
|
$base_uri->alter('view', $toggle_highlight[$selected]),
|
|
|
|
$user);
|
|
|
|
|
|
|
|
|
|
|
|
$href = null;
|
2012-11-09 00:14:44 +01:00
|
|
|
if ($this->getRequest()->getStr('lint') !== null) {
|
2012-11-09 01:13:21 +01:00
|
|
|
$lint_text = pht('Hide %d Lint Message(s)', count($this->lintMessages));
|
2012-11-07 07:46:23 +01:00
|
|
|
$href = $base_uri->alter('lint', null);
|
|
|
|
|
|
|
|
} else if ($this->lintCommit === null) {
|
|
|
|
$lint_text = pht('Lint not Available');
|
|
|
|
|
2013-01-14 22:22:02 +01:00
|
|
|
} else {
|
2012-11-07 07:46:23 +01:00
|
|
|
$lint_text = pht(
|
2013-01-14 22:22:02 +01:00
|
|
|
'Show %d Lint Message(s)',
|
2012-11-07 07:46:23 +01:00
|
|
|
count($this->lintMessages));
|
|
|
|
$href = $this->getDiffusionRequest()->generateURI(array(
|
|
|
|
'action' => 'browse',
|
|
|
|
'commit' => $this->lintCommit,
|
2012-11-09 00:14:44 +01:00
|
|
|
))->alter('lint', '');
|
2012-11-07 07:46:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$lint_button = $this->createViewAction(
|
|
|
|
$lint_text,
|
|
|
|
$href,
|
2012-10-03 19:58:56 +02:00
|
|
|
$user);
|
|
|
|
|
2012-11-07 07:46:23 +01:00
|
|
|
if (!$href) {
|
|
|
|
$lint_button->setDisabled(true);
|
|
|
|
}
|
|
|
|
|
2012-10-03 19:58:56 +02:00
|
|
|
|
|
|
|
$raw_button = $this->createViewAction(
|
|
|
|
pht('View Raw File'),
|
2012-11-07 07:46:23 +01:00
|
|
|
$base_uri->alter('view', 'raw'),
|
2012-10-03 19:58:56 +02:00
|
|
|
$user,
|
|
|
|
'file');
|
|
|
|
|
|
|
|
$edit_button = $this->createEditAction();
|
|
|
|
|
|
|
|
return id(new PhabricatorActionListView())
|
|
|
|
->setUser($user)
|
|
|
|
->addAction($blame_button)
|
|
|
|
->addAction($highlight_button)
|
2012-11-07 07:46:23 +01:00
|
|
|
->addAction($lint_button)
|
2012-10-03 19:58:56 +02:00
|
|
|
->addAction($raw_button)
|
|
|
|
->addAction($edit_button);
|
|
|
|
}
|
|
|
|
|
|
|
|
private function createViewAction(
|
|
|
|
$localized_text,
|
2012-11-07 07:46:23 +01:00
|
|
|
$href,
|
2012-10-03 19:58:56 +02:00
|
|
|
$user,
|
|
|
|
$icon = null) {
|
|
|
|
|
|
|
|
return id(new PhabricatorActionView())
|
|
|
|
->setName($localized_text)
|
|
|
|
->setIcon($icon)
|
|
|
|
->setUser($user)
|
|
|
|
->setRenderAsForm(true)
|
2012-11-07 07:46:23 +01:00
|
|
|
->setHref($href);
|
2012-03-20 03:52:24 +01:00
|
|
|
}
|
|
|
|
|
2012-10-03 19:58:56 +02:00
|
|
|
private function createEditAction() {
|
2012-03-20 03:52:24 +01:00
|
|
|
$request = $this->getRequest();
|
|
|
|
$user = $request->getUser();
|
|
|
|
|
|
|
|
$drequest = $this->getDiffusionRequest();
|
|
|
|
|
|
|
|
$repository = $drequest->getRepository();
|
|
|
|
$path = $drequest->getPath();
|
2012-09-13 20:01:41 +02:00
|
|
|
$line = nonempty((int)$drequest->getLine(), 1);
|
2012-03-20 03:52:24 +01:00
|
|
|
|
2012-04-05 02:53:16 +02:00
|
|
|
$callsign = $repository->getCallsign();
|
|
|
|
$editor_link = $user->loadEditorLink($path, $line, $callsign);
|
2012-03-20 03:52:24 +01:00
|
|
|
|
2012-10-03 19:58:56 +02:00
|
|
|
$action = id(new PhabricatorActionView())
|
|
|
|
->setName(pht('Open in Editor'))
|
|
|
|
->setIcon('edit');
|
|
|
|
|
|
|
|
$action->setHref($editor_link);
|
|
|
|
$action->setDisabled(!$editor_link);
|
|
|
|
|
|
|
|
return $action;
|
2012-03-20 03:52:24 +01:00
|
|
|
}
|
2011-03-13 01:17:34 +01:00
|
|
|
|
2012-04-07 21:01:25 +02:00
|
|
|
private function buildDisplayRows(
|
|
|
|
array $text_list,
|
|
|
|
array $rev_list,
|
|
|
|
array $blame_dict,
|
|
|
|
$needs_blame,
|
|
|
|
DiffusionRequest $drequest,
|
|
|
|
DiffusionFileContentQuery $file_query,
|
|
|
|
$selected) {
|
|
|
|
|
2013-03-05 01:22:30 +01:00
|
|
|
$handles = array();
|
2011-05-18 16:44:53 +02:00
|
|
|
if ($blame_dict) {
|
2012-04-09 08:08:26 +02:00
|
|
|
$epoch_list = ipull(ifilter($blame_dict, 'epoch'), 'epoch');
|
2012-04-08 02:24:35 +02:00
|
|
|
$epoch_min = min($epoch_list);
|
|
|
|
$epoch_max = max($epoch_list);
|
|
|
|
$epoch_range = ($epoch_max - $epoch_min) + 1;
|
2013-03-05 01:22:30 +01:00
|
|
|
$handles = $this->loadViewerHandles(ipull($blame_dict, 'authorPHID'));
|
2011-05-18 16:44:53 +02:00
|
|
|
}
|
2011-04-01 03:28:24 +02:00
|
|
|
|
2012-07-04 23:04:45 +02:00
|
|
|
$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,
|
|
|
|
);
|
|
|
|
}
|
2012-02-25 20:45:51 +01:00
|
|
|
}
|
|
|
|
|
2012-04-08 02:24:35 +02:00
|
|
|
$display = array();
|
|
|
|
|
|
|
|
$line_number = 1;
|
|
|
|
$last_rev = null;
|
|
|
|
$color = null;
|
2011-04-01 03:28:24 +02:00
|
|
|
foreach ($text_list as $k => $line) {
|
2012-04-08 02:24:35 +02:00
|
|
|
$display_line = array(
|
|
|
|
'epoch' => null,
|
|
|
|
'commit' => null,
|
|
|
|
'author' => null,
|
|
|
|
'target' => null,
|
|
|
|
'highlighted' => null,
|
|
|
|
'line' => $line_number,
|
|
|
|
'data' => $line,
|
|
|
|
);
|
|
|
|
|
2013-03-05 23:31:20 +01:00
|
|
|
if ($selected == 'blame') {
|
2011-04-01 03:28:24 +02:00
|
|
|
// 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
|
2012-04-08 02:24:35 +02:00
|
|
|
// is, the more saturated the color.
|
|
|
|
|
|
|
|
$rev = idx($rev_list, $k, $last_rev);
|
|
|
|
|
2011-04-01 03:28:24 +02:00
|
|
|
if ($last_rev == $rev) {
|
2012-04-08 02:24:35 +02:00
|
|
|
$display_line['color'] = $color;
|
2011-03-26 20:42:12 +01:00
|
|
|
} else {
|
2012-04-08 02:24:35 +02:00
|
|
|
$blame = $blame_dict[$rev];
|
2011-04-01 03:28:24 +02:00
|
|
|
|
2012-04-09 08:08:26 +02:00
|
|
|
if (!isset($blame['epoch'])) {
|
|
|
|
$color = '#ffd'; // Render as warning.
|
|
|
|
} else {
|
|
|
|
$color_ratio = ($blame['epoch'] - $epoch_min) / $epoch_range;
|
2013-03-08 07:38:08 +01:00
|
|
|
$color_value = 0xE6 * (1.0 - $color_ratio);
|
2012-04-09 08:08:26 +02:00
|
|
|
$color = sprintf(
|
|
|
|
'#%02x%02x%02x',
|
|
|
|
$color_value,
|
|
|
|
0xF6,
|
|
|
|
$color_value);
|
|
|
|
}
|
2011-03-26 20:42:12 +01:00
|
|
|
|
2012-04-09 08:08:26 +02:00
|
|
|
$display_line['epoch'] = idx($blame, 'epoch');
|
2012-04-08 02:24:35 +02:00
|
|
|
$display_line['color'] = $color;
|
|
|
|
$display_line['commit'] = $rev;
|
2011-04-02 00:34:45 +02:00
|
|
|
|
2013-03-05 01:22:30 +01:00
|
|
|
$author_phid = idx($blame, 'authorPHID');
|
|
|
|
if ($author_phid && $handles[$author_phid]) {
|
|
|
|
$author_link = $handles[$author_phid]->renderLink();
|
2011-10-18 21:58:45 +02:00
|
|
|
} else {
|
2013-01-18 03:43:35 +01:00
|
|
|
$author_link = phutil_tag(
|
2012-04-08 02:24:35 +02:00
|
|
|
'span',
|
|
|
|
array(
|
|
|
|
),
|
2013-01-18 03:43:35 +01:00
|
|
|
$blame['author']);
|
2011-10-18 21:58:45 +02:00
|
|
|
}
|
2012-04-08 02:24:35 +02:00
|
|
|
$display_line['author'] = $author_link;
|
|
|
|
|
2011-04-01 03:28:24 +02:00
|
|
|
$last_rev = $rev;
|
2011-03-26 20:42:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-04 23:04:45 +02:00
|
|
|
if ($line_arr) {
|
|
|
|
if ($line_number == $line_arr[0]['min']) {
|
2012-04-08 02:24:35 +02:00
|
|
|
$display_line['target'] = true;
|
|
|
|
}
|
2012-07-04 23:04:45 +02:00
|
|
|
foreach ($line_arr as $range) {
|
|
|
|
if ($line_number >= $range['min'] &&
|
|
|
|
$line_number <= $range['max']) {
|
|
|
|
$display_line['highlighted'] = true;
|
|
|
|
}
|
2012-02-25 20:45:51 +01:00
|
|
|
}
|
2011-03-26 20:42:12 +01:00
|
|
|
}
|
|
|
|
|
2012-04-08 02:24:35 +02:00
|
|
|
$display[] = $display_line;
|
|
|
|
++$line_number;
|
|
|
|
}
|
|
|
|
|
2012-04-10 10:32:47 +02:00
|
|
|
$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');
|
|
|
|
}
|
2012-04-08 02:24:35 +02:00
|
|
|
|
2012-06-23 01:52:08 +02:00
|
|
|
$revision_ids = id(new DifferentialRevision())
|
|
|
|
->loadIDsByCommitPHIDs(mpull($commits, 'getPHID'));
|
2012-06-21 21:48:45 +02:00
|
|
|
$revisions = array();
|
2012-06-23 01:52:08 +02:00
|
|
|
if ($revision_ids) {
|
|
|
|
$revisions = id(new DifferentialRevision())->loadAllWhere(
|
|
|
|
'id IN (%Ld)',
|
|
|
|
$revision_ids);
|
2012-06-21 21:48:45 +02:00
|
|
|
}
|
|
|
|
|
2012-04-08 02:24:35 +02:00
|
|
|
$request = $this->getRequest();
|
|
|
|
$user = $request->getUser();
|
|
|
|
|
Use "user-select: none" to provide a visual cue about copy/paste JS magic
Summary:
- For line numbers, use "user-select: none" to make them unselectable. This provides a stronger visual cue that copy/paste is enchanted.
- In Paste, make it look sensible again after the blame-on-blame refactor in Diffusion. See also TODO to share this code formally.
- In Diffusion, use the "phabricator-oncopy" behavior.
NOTE: I left blame/commit columns selectable in Diffusion, since you might reasonably want to copy/paste them?
NOTE: In Differential, the left side of the diff still highlights, even though it will be copied only if you select part of a line on the left and nothing else. But this seemed like a reasonable behavior, so I left it.
Test Plan:
- Looked at Paste. Saw a nice line number column. Selected text, got the expected selection. Copied text, got the expected copy.
- Looked at Diffusion. Saw a nice line number column, still. Selected text, got expected selection. Copied text, got expected copy.
- Looked at Differential. Highlighted stuff, got expected results. Copied stuff, got expected results.
Reviewers: btrahan, vrana, jungejason
Reviewed By: vrana
CC: aran
Maniphest Tasks: T1123
Differential Revision: https://secure.phabricator.com/D2242
2012-04-17 00:55:16 +02:00
|
|
|
Javelin::initBehavior('phabricator-oncopy', array());
|
|
|
|
|
2012-11-07 07:46:23 +01:00
|
|
|
$engine = null;
|
|
|
|
$inlines = array();
|
2012-11-09 00:14:44 +01:00
|
|
|
if ($this->getRequest()->getStr('lint') !== null && $this->lintMessages) {
|
2012-11-07 07:46:23 +01:00
|
|
|
$engine = new PhabricatorMarkupEngine();
|
|
|
|
$engine->setViewer($user);
|
|
|
|
|
|
|
|
foreach ($this->lintMessages as $message) {
|
|
|
|
$inline = id(new PhabricatorAuditInlineComment())
|
2012-11-10 02:45:19 +01:00
|
|
|
->setID($message['id'])
|
2012-11-09 01:13:21 +01:00
|
|
|
->setSyntheticAuthor(
|
|
|
|
ArcanistLintSeverity::getStringForSeverity($message['severity']).
|
|
|
|
' '.$message['code'].' ('.$message['name'].')')
|
2012-11-07 07:46:23 +01:00
|
|
|
->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()),
|
2013-03-05 23:31:20 +01:00
|
|
|
($selected == 'blame'),
|
2012-11-07 07:46:23 +01:00
|
|
|
$engine);
|
|
|
|
|
2012-04-08 02:24:35 +02:00
|
|
|
foreach ($display as $line) {
|
|
|
|
|
|
|
|
$line_href = $drequest->generateURI(
|
Fix many encoding and architecture problems in Diffusion request and URI handling
Summary:
Diffusion request/uri handling is currently a big, hastily ported mess. In particular, it has:
- Tons and tons of duplicated code.
- Bugs with handling unusual branch and file names.
- An excessively large (and yet insufficiently expressive) API on DiffusionRequest, including a nonsensical concrete base class.
- Other tools were doing hacky things like passing ":" branch names.
This diff attempts to fix these issues.
- Make the base class abstract (it was concrete ONLY for "/diffusion/").
- Move all URI generation to DiffusionRequest. Make the core static. Add unit tests.
- Delete the 300 copies of URI generation code throughout Diffusion.
- Move all URI parsing to DiffusionRequest. Make the core static. Add unit tests.
- Add an appropriate static initializer for other callers.
- Convert all code calling `newFromAphrontRequestDictionary` outside of Diffusion to the new `newFromDictionary` API.
- Refactor static initializers to be sensibly-sized.
- Refactor derived DiffusionRequest classes to remove duplicated code.
- Properly encode branch names (fixes branches with "/", see <https://github.com/facebook/phabricator/issues/100>).
- Properly encode path names (fixes issues in D1742).
- Properly escape delimiter characters ";" and "$" in path names so files like "$100" are not interpreted as "line 100".
- Fix a couple warnings.
- Fix a couple lint issues.
- Fix a bug where we would not parse filenames with spaces in them correctly in the Git browse query.
- Fix a bug where Git change queries would fail unnecessarily.
- Provide or improve some documentation.
This thing is pretty gigantic but also kind of hard to split up. If it's unreasonably difficult to review, let me know and I can take a stab at it though.
This supplants D1742.
Test Plan:
- Used home, repository, branch, browse, change, history, diff (ajax), lastmodified (ajax) views of Diffusion.
- Used Owners typeaheads and search.
- Used diffusion.getrecentcommitsbypath method.
- Pushed a change to an absurdly-named file on an absurdly-named branch, everything worked properly.
{F9185}
Reviewers: nh, vrana, btrahan
Reviewed By: btrahan
CC: aran, epriestley
Differential Revision: https://secure.phabricator.com/D1921
2012-03-20 03:52:14 +01:00
|
|
|
array(
|
2012-04-08 02:24:35 +02:00
|
|
|
'action' => 'browse',
|
|
|
|
'line' => $line['line'],
|
|
|
|
'stable' => true,
|
Fix many encoding and architecture problems in Diffusion request and URI handling
Summary:
Diffusion request/uri handling is currently a big, hastily ported mess. In particular, it has:
- Tons and tons of duplicated code.
- Bugs with handling unusual branch and file names.
- An excessively large (and yet insufficiently expressive) API on DiffusionRequest, including a nonsensical concrete base class.
- Other tools were doing hacky things like passing ":" branch names.
This diff attempts to fix these issues.
- Make the base class abstract (it was concrete ONLY for "/diffusion/").
- Move all URI generation to DiffusionRequest. Make the core static. Add unit tests.
- Delete the 300 copies of URI generation code throughout Diffusion.
- Move all URI parsing to DiffusionRequest. Make the core static. Add unit tests.
- Add an appropriate static initializer for other callers.
- Convert all code calling `newFromAphrontRequestDictionary` outside of Diffusion to the new `newFromDictionary` API.
- Refactor static initializers to be sensibly-sized.
- Refactor derived DiffusionRequest classes to remove duplicated code.
- Properly encode branch names (fixes branches with "/", see <https://github.com/facebook/phabricator/issues/100>).
- Properly encode path names (fixes issues in D1742).
- Properly escape delimiter characters ";" and "$" in path names so files like "$100" are not interpreted as "line 100".
- Fix a couple warnings.
- Fix a couple lint issues.
- Fix a bug where we would not parse filenames with spaces in them correctly in the Git browse query.
- Fix a bug where Git change queries would fail unnecessarily.
- Provide or improve some documentation.
This thing is pretty gigantic but also kind of hard to split up. If it's unreasonably difficult to review, let me know and I can take a stab at it though.
This supplants D1742.
Test Plan:
- Used home, repository, branch, browse, change, history, diff (ajax), lastmodified (ajax) views of Diffusion.
- Used Owners typeaheads and search.
- Used diffusion.getrecentcommitsbypath method.
- Pushed a change to an absurdly-named file on an absurdly-named branch, everything worked properly.
{F9185}
Reviewers: nh, vrana, btrahan
Reviewed By: btrahan
CC: aran, epriestley
Differential Revision: https://secure.phabricator.com/D1921
2012-03-20 03:52:14 +01:00
|
|
|
));
|
|
|
|
|
2012-04-08 02:24:35 +02:00
|
|
|
$blame = array();
|
2013-03-05 23:31:20 +01:00
|
|
|
$style = null;
|
|
|
|
if (array_key_exists('color', $line)) {
|
|
|
|
if ($line['color']) {
|
|
|
|
$style = 'background: '.$line['color'].';';
|
|
|
|
}
|
2012-04-08 02:24:35 +02:00
|
|
|
|
|
|
|
$before_link = null;
|
|
|
|
$commit_link = null;
|
2012-06-21 21:48:45 +02:00
|
|
|
$revision_link = null;
|
2012-04-08 02:24:35 +02:00
|
|
|
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');
|
|
|
|
|
2013-01-25 21:57:17 +01:00
|
|
|
$commit_link = javelin_tag(
|
2012-04-08 02:24:35 +02:00
|
|
|
'a',
|
|
|
|
array(
|
|
|
|
'href' => $drequest->generateURI(
|
|
|
|
array(
|
|
|
|
'action' => 'commit',
|
|
|
|
'commit' => $line['commit'],
|
|
|
|
)),
|
|
|
|
'sigil' => 'has-tooltip',
|
|
|
|
'meta' => array(
|
|
|
|
'tip' => $tooltip,
|
|
|
|
'align' => 'E',
|
|
|
|
'size' => 600,
|
|
|
|
),
|
|
|
|
),
|
2013-01-25 21:57:17 +01:00
|
|
|
phutil_utf8_shorten($line['commit'], 9, ''));
|
2012-04-08 02:24:35 +02:00
|
|
|
|
2012-07-12 02:02:15 +02:00
|
|
|
$revision_id = null;
|
|
|
|
if (idx($commits, $commit)) {
|
|
|
|
$revision_id = idx($revision_ids, $commits[$commit]->getPHID());
|
|
|
|
}
|
|
|
|
|
2012-06-21 21:48:45 +02:00
|
|
|
if ($revision_id) {
|
|
|
|
$revision = idx($revisions, $revision_id);
|
|
|
|
if (!$revision) {
|
|
|
|
$tooltip = '(Invalid revision)';
|
|
|
|
} else {
|
|
|
|
$tooltip =
|
|
|
|
phabricator_date($revision->getDateModified(), $user).
|
|
|
|
" \xC2\xB7 ".
|
|
|
|
$revision->getTitle();
|
|
|
|
}
|
2013-01-25 21:57:17 +01:00
|
|
|
$revision_link = javelin_tag(
|
2012-06-21 21:48:45 +02:00
|
|
|
'a',
|
|
|
|
array(
|
|
|
|
'href' => '/D'.$revision_id,
|
|
|
|
'sigil' => 'has-tooltip',
|
|
|
|
'meta' => array(
|
|
|
|
'tip' => $tooltip,
|
|
|
|
'align' => 'E',
|
|
|
|
'size' => 600,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
'D'.$revision_id);
|
|
|
|
}
|
|
|
|
|
2012-09-29 01:41:39 +02:00
|
|
|
$uri = $line_href->alter('before', $commit);
|
2013-01-25 21:57:17 +01:00
|
|
|
$before_link = javelin_tag(
|
2012-04-08 02:24:35 +02:00
|
|
|
'a',
|
|
|
|
array(
|
2012-09-29 01:41:39 +02:00
|
|
|
'href' => $uri->setQueryParam('view', 'blame'),
|
2012-04-08 02:24:35 +02:00
|
|
|
'sigil' => 'has-tooltip',
|
|
|
|
'meta' => array(
|
|
|
|
'tip' => 'Skip Past This Commit',
|
|
|
|
'align' => 'E',
|
|
|
|
'size' => 300,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
"\xC2\xAB");
|
|
|
|
}
|
|
|
|
|
2013-01-18 09:32:58 +01:00
|
|
|
$blame[] = phutil_tag(
|
2012-04-08 02:24:35 +02:00
|
|
|
'th',
|
|
|
|
array(
|
|
|
|
'class' => 'diffusion-blame-link',
|
2013-03-05 23:31:20 +01:00
|
|
|
'style' => $style,
|
2012-04-08 02:24:35 +02:00
|
|
|
),
|
|
|
|
$before_link);
|
|
|
|
|
2013-01-18 09:32:58 +01:00
|
|
|
$blame[] = phutil_tag(
|
2012-04-08 02:24:35 +02:00
|
|
|
'th',
|
|
|
|
array(
|
|
|
|
'class' => 'diffusion-rev-link',
|
2013-03-05 23:31:20 +01:00
|
|
|
'style' => $style,
|
2012-04-08 02:24:35 +02:00
|
|
|
),
|
|
|
|
$commit_link);
|
|
|
|
|
2013-01-18 09:32:58 +01:00
|
|
|
$blame[] = phutil_tag(
|
2012-06-21 21:48:45 +02:00
|
|
|
'th',
|
|
|
|
array(
|
|
|
|
'class' => 'diffusion-rev-link',
|
2013-03-05 23:31:20 +01:00
|
|
|
'style' => $style,
|
2012-06-21 21:48:45 +02:00
|
|
|
),
|
|
|
|
$revision_link);
|
|
|
|
|
2013-01-18 09:32:58 +01:00
|
|
|
$blame[] = phutil_tag(
|
2012-04-08 02:24:35 +02:00
|
|
|
'th',
|
|
|
|
array(
|
|
|
|
'class' => 'diffusion-author-link',
|
2013-03-05 23:31:20 +01:00
|
|
|
'style' => $style,
|
2012-04-08 02:24:35 +02:00
|
|
|
),
|
|
|
|
idx($line, 'author'));
|
Fix many encoding and architecture problems in Diffusion request and URI handling
Summary:
Diffusion request/uri handling is currently a big, hastily ported mess. In particular, it has:
- Tons and tons of duplicated code.
- Bugs with handling unusual branch and file names.
- An excessively large (and yet insufficiently expressive) API on DiffusionRequest, including a nonsensical concrete base class.
- Other tools were doing hacky things like passing ":" branch names.
This diff attempts to fix these issues.
- Make the base class abstract (it was concrete ONLY for "/diffusion/").
- Move all URI generation to DiffusionRequest. Make the core static. Add unit tests.
- Delete the 300 copies of URI generation code throughout Diffusion.
- Move all URI parsing to DiffusionRequest. Make the core static. Add unit tests.
- Add an appropriate static initializer for other callers.
- Convert all code calling `newFromAphrontRequestDictionary` outside of Diffusion to the new `newFromDictionary` API.
- Refactor static initializers to be sensibly-sized.
- Refactor derived DiffusionRequest classes to remove duplicated code.
- Properly encode branch names (fixes branches with "/", see <https://github.com/facebook/phabricator/issues/100>).
- Properly encode path names (fixes issues in D1742).
- Properly escape delimiter characters ";" and "$" in path names so files like "$100" are not interpreted as "line 100".
- Fix a couple warnings.
- Fix a couple lint issues.
- Fix a bug where we would not parse filenames with spaces in them correctly in the Git browse query.
- Fix a bug where Git change queries would fail unnecessarily.
- Provide or improve some documentation.
This thing is pretty gigantic but also kind of hard to split up. If it's unreasonably difficult to review, let me know and I can take a stab at it though.
This supplants D1742.
Test Plan:
- Used home, repository, branch, browse, change, history, diff (ajax), lastmodified (ajax) views of Diffusion.
- Used Owners typeaheads and search.
- Used diffusion.getrecentcommitsbypath method.
- Pushed a change to an absurdly-named file on an absurdly-named branch, everything worked properly.
{F9185}
Reviewers: nh, vrana, btrahan
Reviewed By: btrahan
CC: aran, epriestley
Differential Revision: https://secure.phabricator.com/D1921
2012-03-20 03:52:14 +01:00
|
|
|
}
|
|
|
|
|
2013-01-18 03:43:35 +01:00
|
|
|
$line_link = phutil_tag(
|
2011-03-26 20:42:12 +01:00
|
|
|
'a',
|
|
|
|
array(
|
2012-04-08 02:24:35 +02:00
|
|
|
'href' => $line_href,
|
|
|
|
),
|
2013-01-18 03:43:35 +01:00
|
|
|
$line['line']);
|
2012-04-08 02:24:35 +02:00
|
|
|
|
2013-01-25 21:57:17 +01:00
|
|
|
$blame[] = javelin_tag(
|
2012-04-08 02:24:35 +02:00
|
|
|
'th',
|
|
|
|
array(
|
|
|
|
'class' => 'diffusion-line-link',
|
2012-08-04 18:47:51 +02:00
|
|
|
'sigil' => 'diffusion-line-link',
|
2013-03-05 23:31:20 +01:00
|
|
|
'style' => $style,
|
2012-04-08 02:24:35 +02:00
|
|
|
),
|
|
|
|
$line_link);
|
|
|
|
|
2012-08-04 18:47:51 +02:00
|
|
|
Javelin::initBehavior('diffusion-line-linker');
|
|
|
|
|
2012-04-08 02:24:35 +02:00
|
|
|
if ($line['target']) {
|
|
|
|
Javelin::initBehavior(
|
|
|
|
'diffusion-jump-to',
|
|
|
|
array(
|
|
|
|
'target' => 'scroll_target',
|
|
|
|
));
|
2013-01-31 18:08:02 +01:00
|
|
|
$anchor_text = phutil_tag(
|
|
|
|
'a',
|
|
|
|
array(
|
|
|
|
'id' => 'scroll_target',
|
|
|
|
),
|
|
|
|
'');
|
2012-04-08 02:24:35 +02:00
|
|
|
} else {
|
|
|
|
$anchor_text = null;
|
|
|
|
}
|
|
|
|
|
2013-01-31 18:08:02 +01:00
|
|
|
$blame[] = phutil_tag(
|
2012-04-08 02:24:35 +02:00
|
|
|
'td',
|
|
|
|
array(
|
2011-03-26 20:42:12 +01:00
|
|
|
),
|
2013-01-31 18:08:02 +01:00
|
|
|
array(
|
|
|
|
$anchor_text,
|
|
|
|
|
|
|
|
// NOTE: See phabricator-oncopy behavior.
|
|
|
|
"\xE2\x80\x8B",
|
|
|
|
|
|
|
|
// TODO: [HTML] Not ideal.
|
|
|
|
phutil_safe_html($line['data']),
|
|
|
|
));
|
2011-03-26 20:42:12 +01:00
|
|
|
|
2013-01-18 09:32:58 +01:00
|
|
|
$rows[] = phutil_tag(
|
2012-04-08 02:24:35 +02:00
|
|
|
'tr',
|
|
|
|
array(
|
2012-08-04 18:47:51 +02:00
|
|
|
'class' => ($line['highlighted'] ? 'highlighted' : null),
|
2012-04-08 02:24:35 +02:00
|
|
|
),
|
2013-01-18 09:32:58 +01:00
|
|
|
$blame);
|
2012-11-07 07:46:23 +01:00
|
|
|
|
|
|
|
$rows = array_merge($rows, $this->renderInlines(
|
|
|
|
idx($inlines, $line['line'], array()),
|
2013-03-05 23:31:20 +01:00
|
|
|
($selected == 'blame'),
|
2012-11-07 07:46:23 +01:00
|
|
|
$engine));
|
2011-03-26 20:42:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return $rows;
|
2011-03-08 18:54:55 +01:00
|
|
|
}
|
2011-04-01 03:28:24 +02:00
|
|
|
|
2012-11-07 07:46:23 +01:00
|
|
|
private function renderInlines(array $inlines, $needs_blame, $engine) {
|
|
|
|
$rows = array();
|
|
|
|
foreach ($inlines as $inline) {
|
|
|
|
$inline_view = id(new DifferentialInlineCommentView())
|
|
|
|
->setMarkupEngine($engine)
|
|
|
|
->setInlineComment($inline)
|
|
|
|
->render();
|
2013-02-02 14:15:30 +01:00
|
|
|
$row = array_fill(0, ($needs_blame ? 5 : 1), phutil_tag('th'));
|
|
|
|
$row[] = phutil_tag('td', array(), $inline_view);
|
|
|
|
$rows[] = phutil_tag('tr', array('class' => 'inline'), $row);
|
2012-11-07 07:46:23 +01:00
|
|
|
}
|
|
|
|
return $rows;
|
|
|
|
}
|
2011-04-01 03:28:24 +02:00
|
|
|
|
2012-03-20 03:52:24 +01:00
|
|
|
private function loadFileForData($path, $data) {
|
2012-07-09 19:38:25 +02:00
|
|
|
return PhabricatorFile::buildFromFileDataOrHash(
|
|
|
|
$data,
|
|
|
|
array(
|
|
|
|
'name' => basename($path),
|
2013-02-20 22:33:47 +01:00
|
|
|
'ttl' => time() + 60 * 60 * 24,
|
2012-07-09 19:38:25 +02:00
|
|
|
));
|
2012-03-20 03:52:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private function buildRawResponse($path, $data) {
|
|
|
|
$file = $this->loadFileForData($path, $data);
|
|
|
|
return id(new AphrontRedirectResponse())->setURI($file->getBestURI());
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildImageCorpus($file_uri) {
|
2012-10-31 19:43:17 +01:00
|
|
|
$properties = new PhabricatorPropertyListView();
|
|
|
|
|
|
|
|
$properties->addProperty(
|
|
|
|
pht('Image'),
|
2013-01-18 03:39:02 +01:00
|
|
|
phutil_tag(
|
2012-03-20 03:52:24 +01:00
|
|
|
'img',
|
|
|
|
array(
|
|
|
|
'src' => $file_uri,
|
|
|
|
)));
|
2012-10-31 19:43:17 +01:00
|
|
|
|
|
|
|
$actions = id(new PhabricatorActionListView())
|
|
|
|
->setUser($this->getRequest()->getUser())
|
|
|
|
->addAction($this->createEditAction());
|
|
|
|
|
|
|
|
return array($actions, $properties);
|
2012-03-20 03:52:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private function buildBinaryCorpus($file_uri, $data) {
|
2012-10-31 19:43:17 +01:00
|
|
|
$properties = new PhabricatorPropertyListView();
|
|
|
|
|
2012-11-13 01:35:26 +01:00
|
|
|
$size = strlen($data);
|
2012-10-31 19:43:17 +01:00
|
|
|
$properties->addTextContent(
|
2013-01-31 17:44:21 +01:00
|
|
|
pht(
|
|
|
|
'This is a binary file. It is %s byte(s) in length.',
|
|
|
|
new PhutilNumber($size)));
|
2012-10-31 19:43:17 +01:00
|
|
|
|
|
|
|
$actions = id(new PhabricatorActionListView())
|
|
|
|
->setUser($this->getRequest()->getUser())
|
|
|
|
->addAction($this->createEditAction())
|
2013-01-29 20:01:47 +01:00
|
|
|
->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setName(pht('Download Binary File...'))
|
|
|
|
->setIcon('download')
|
|
|
|
->setHref($file_uri));
|
2012-10-31 19:43:17 +01:00
|
|
|
|
|
|
|
return array($actions, $properties);
|
|
|
|
|
2012-03-20 03:52:24 +01:00
|
|
|
}
|
|
|
|
|
2012-04-08 02:24:35 +02:00
|
|
|
private function buildBeforeResponse($before) {
|
|
|
|
$request = $this->getRequest();
|
|
|
|
$drequest = $this->getDiffusionRequest();
|
|
|
|
|
2012-04-24 03:16:38 +02:00
|
|
|
// 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) {
|
2012-09-28 23:36:47 +02:00
|
|
|
$rename_query = new DiffusionRenameHistoryQuery();
|
|
|
|
$rename_query->setRequest($drequest);
|
2012-04-24 03:16:38 +02:00
|
|
|
$rename_query->setOldCommit($grandparent->getCommitIdentifier());
|
|
|
|
$old_filename = $rename_query->loadOldFilename();
|
|
|
|
$was_created = $rename_query->getWasCreated();
|
|
|
|
}
|
|
|
|
}
|
2012-04-08 02:24:35 +02:00
|
|
|
|
2012-04-24 03:16:38 +02:00
|
|
|
$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';
|
|
|
|
}
|
2012-04-08 02:24:35 +02:00
|
|
|
|
2012-04-24 03:16:38 +02:00
|
|
|
$path = $drequest->getPath();
|
|
|
|
$renamed = null;
|
|
|
|
if ($old_filename !== null &&
|
2012-09-28 23:36:47 +02:00
|
|
|
$old_filename !== '/'.$path) {
|
2012-04-24 03:16:38 +02:00
|
|
|
$renamed = $path;
|
|
|
|
$path = $old_filename;
|
|
|
|
}
|
2012-04-08 02:24:35 +02:00
|
|
|
|
2012-07-27 00:39:13 +02:00
|
|
|
$line = null;
|
|
|
|
// If there's a follow error, drop the line so the user sees the message.
|
|
|
|
if (!$follow) {
|
|
|
|
$line = $this->getBeforeLineNumber($target_commit);
|
|
|
|
}
|
|
|
|
|
2012-04-08 02:24:35 +02:00
|
|
|
$before_uri = $drequest->generateURI(
|
|
|
|
array(
|
|
|
|
'action' => 'browse',
|
2012-04-24 03:16:38 +02:00
|
|
|
'commit' => $target_commit,
|
2012-07-27 00:39:13 +02:00
|
|
|
'line' => $line,
|
2012-04-24 03:16:38 +02:00
|
|
|
'path' => $path,
|
2012-04-08 02:24:35 +02:00
|
|
|
));
|
|
|
|
|
|
|
|
$before_uri->setQueryParams($request->getRequestURI()->getQueryParams());
|
|
|
|
$before_uri = $before_uri->alter('before', null);
|
2012-04-24 03:16:38 +02:00
|
|
|
$before_uri = $before_uri->alter('renamed', $renamed);
|
|
|
|
$before_uri = $before_uri->alter('follow', $follow);
|
2012-04-08 02:24:35 +02:00
|
|
|
|
|
|
|
return id(new AphrontRedirectResponse())->setURI($before_uri);
|
|
|
|
}
|
2011-04-02 00:34:45 +02:00
|
|
|
|
2012-07-27 00:39:13 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-24 03:16:38 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2011-03-08 18:54:55 +01:00
|
|
|
}
|