mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 14:52:41 +01:00
Support rendering arbitrary sections in the middle of a Harbormaster build log so links to line 3500 work
Summary: Depends on D19162. Ref T13088. When a user links to `$1234`, we need to render a default view of the log with a piece at the head, a piece at the end, and a piece in the middle. We also need to figure out the offset for line 1234, or multiple offsets for "1234-2345". Since the logic views/reads mostly anticipated this it isn't too much of a mess, although there are a couple of bugs this exposes with view specifications that use combinations of parameters which were previously impossible. Test Plan: Viewed a large log with no line marker. Viewed `$1`. Viewed `$end`. Viewed `$35-40`, etc. Expanded context around logs. Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam Maniphest Tasks: T13088 Differential Revision: https://secure.phabricator.com/D19163
This commit is contained in:
parent
4466402c5a
commit
49af4165bc
5 changed files with 202 additions and 33 deletions
|
@ -416,7 +416,7 @@ return array(
|
|||
'rsrc/js/application/drydock/drydock-live-operation-status.js' => '901935ef',
|
||||
'rsrc/js/application/files/behavior-icon-composer.js' => '8499b6ab',
|
||||
'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888',
|
||||
'rsrc/js/application/harbormaster/behavior-harbormaster-log.js' => '796a8803',
|
||||
'rsrc/js/application/harbormaster/behavior-harbormaster-log.js' => 'ab1173d1',
|
||||
'rsrc/js/application/herald/HeraldRuleEditor.js' => 'dca75c0e',
|
||||
'rsrc/js/application/herald/PathTypeahead.js' => 'f7fc67ec',
|
||||
'rsrc/js/application/herald/herald-rule-editor.js' => '7ebaeed3',
|
||||
|
@ -636,7 +636,7 @@ return array(
|
|||
'javelin-behavior-event-all-day' => 'b41537c9',
|
||||
'javelin-behavior-fancy-datepicker' => 'ecf4e799',
|
||||
'javelin-behavior-global-drag-and-drop' => '960f6a39',
|
||||
'javelin-behavior-harbormaster-log' => '796a8803',
|
||||
'javelin-behavior-harbormaster-log' => 'ab1173d1',
|
||||
'javelin-behavior-herald-rule-editor' => '7ebaeed3',
|
||||
'javelin-behavior-high-security-warning' => 'a464fe03',
|
||||
'javelin-behavior-history-install' => '7ee2b591',
|
||||
|
@ -1526,9 +1526,6 @@ return array(
|
|||
'javelin-behavior',
|
||||
'javelin-quicksand',
|
||||
),
|
||||
'796a8803' => array(
|
||||
'javelin-behavior',
|
||||
),
|
||||
'7a68dda3' => array(
|
||||
'owners-path-editor',
|
||||
'javelin-behavior',
|
||||
|
@ -1768,6 +1765,9 @@ return array(
|
|||
'javelin-util',
|
||||
'phabricator-prefab',
|
||||
),
|
||||
'ab1173d1' => array(
|
||||
'javelin-behavior',
|
||||
),
|
||||
'ab2f381b' => array(
|
||||
'javelin-request',
|
||||
'javelin-behavior',
|
||||
|
|
|
@ -16,6 +16,8 @@ final class HarbormasterBuildLogRenderController
|
|||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$highlight_range = $request->getURILineRange('lines', 1000);
|
||||
|
||||
$log_size = $this->getTotalByteLength($log);
|
||||
|
||||
$head_lines = $request->getInt('head');
|
||||
|
@ -65,6 +67,16 @@ final class HarbormasterBuildLogRenderController
|
|||
);
|
||||
}
|
||||
|
||||
if ($highlight_range) {
|
||||
$highlight_views = $this->getHighlightViews(
|
||||
$log,
|
||||
$highlight_range,
|
||||
$log_size);
|
||||
foreach ($highlight_views as $highlight_view) {
|
||||
$views[] = $highlight_view;
|
||||
}
|
||||
}
|
||||
|
||||
if ($tail_lines > 0) {
|
||||
$views[] = array(
|
||||
'offset' => $tail_offset,
|
||||
|
@ -86,10 +98,11 @@ final class HarbormasterBuildLogRenderController
|
|||
|
||||
$direction = $read['direction'];
|
||||
if ($direction < 0) {
|
||||
if ($offset > $read_length) {
|
||||
$offset -= $read_length;
|
||||
if ($offset < 0) {
|
||||
} else {
|
||||
$read_length = $offset;
|
||||
$offset = 0;
|
||||
$read_length = $log_size;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,9 +228,11 @@ final class HarbormasterBuildLogRenderController
|
|||
}
|
||||
|
||||
$limit = $view['limit'];
|
||||
if ($limit !== null) {
|
||||
if ($limit < ($view_offset + $view_length)) {
|
||||
$view_length = ($limit - $view_offset);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$view_offset = $data_offset;
|
||||
$view_length = $data_length;
|
||||
|
@ -226,11 +241,13 @@ final class HarbormasterBuildLogRenderController
|
|||
}
|
||||
|
||||
$limit = $view['limit'];
|
||||
if ($limit !== null) {
|
||||
if ($limit > $view_offset) {
|
||||
$view_length -= ($limit - $view_offset);
|
||||
$view_offset = $limit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$views[$view_key] += array(
|
||||
'viewOffset' => $view_offset,
|
||||
|
@ -325,7 +342,6 @@ final class HarbormasterBuildLogRenderController
|
|||
}
|
||||
|
||||
$uri = $log->getURI();
|
||||
$highlight_range = $request->getURIData('lines');
|
||||
|
||||
$rows = array();
|
||||
foreach ($render as $range) {
|
||||
|
@ -339,6 +355,16 @@ final class HarbormasterBuildLogRenderController
|
|||
$display_line = ($line['line'] + 1);
|
||||
$display_text = ($line['data']);
|
||||
|
||||
$cell_attr = array();
|
||||
if ($highlight_range) {
|
||||
if (($display_line >= $highlight_range[0]) &&
|
||||
($display_line <= $highlight_range[1])) {
|
||||
$cell_attr = array(
|
||||
'class' => 'phabricator-source-highlight',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$display_line = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
|
@ -347,7 +373,7 @@ final class HarbormasterBuildLogRenderController
|
|||
$display_line);
|
||||
|
||||
$line_cell = phutil_tag('th', array(), $display_line);
|
||||
$text_cell = phutil_tag('td', array(), $display_text);
|
||||
$text_cell = phutil_tag('td', $cell_attr, $display_text);
|
||||
|
||||
$rows[] = phutil_tag(
|
||||
'tr',
|
||||
|
@ -557,25 +583,43 @@ final class HarbormasterBuildLogRenderController
|
|||
$vs = $vview['viewOffset'];
|
||||
$ve = $vs + $vview['viewLength'];
|
||||
|
||||
// Don't merge if one of the slices starts at a byte offset
|
||||
// significantly after the other ends.
|
||||
if (($vs > $ue + $body_bytes) || ($us > $ve + $body_bytes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$uss = $uview['sliceOffset'];
|
||||
$use = $uss + $uview['sliceLength'];
|
||||
|
||||
$vss = $vview['sliceOffset'];
|
||||
$vse = $vss + $vview['sliceLength'];
|
||||
|
||||
if ($ue <= $vs) {
|
||||
if (($ue + $body_bytes) >= $vs) {
|
||||
if (($use + $body_lines) >= $vss) {
|
||||
// Don't merge if one of the slices starts at a line offset
|
||||
// significantly after the other ends.
|
||||
if ($uss > ($vse + $body_lines) || $vss > ($use + $body_lines)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// These views are overlapping or nearly overlapping, so we merge
|
||||
// them. We merge views even if they aren't exactly adjacent since
|
||||
// it's silly to render an "expand more" which only expands a couple
|
||||
// of lines.
|
||||
|
||||
$offset = min($us, $vs);
|
||||
$length = max($ue, $ve) - $offset;
|
||||
|
||||
$slice_offset = min($uss, $vss);
|
||||
$slice_length = max($use, $vse) - $slice_offset;
|
||||
|
||||
$views[$ukey] = array(
|
||||
'sliceLength' => ($vse - $uss),
|
||||
'viewLength' => ($ve - $us),
|
||||
'viewOffset' => $offset,
|
||||
'viewLength' => $length,
|
||||
'sliceOffset' => $slice_offset,
|
||||
'sliceLength' => $slice_length,
|
||||
) + $views[$ukey];
|
||||
|
||||
unset($views[$vkey]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -603,7 +647,7 @@ final class HarbormasterBuildLogRenderController
|
|||
'meta' => array(
|
||||
'headOffset' => $range['head'],
|
||||
'tailOffset' => $range['tail'],
|
||||
'head' => 4,
|
||||
'head' => 128,
|
||||
'tail' => 0,
|
||||
),
|
||||
),
|
||||
|
@ -620,8 +664,8 @@ final class HarbormasterBuildLogRenderController
|
|||
'meta' => array(
|
||||
'headOffset' => $range['head'],
|
||||
'tailOffset' => $range['tail'],
|
||||
'head' => 2,
|
||||
'tail' => 2,
|
||||
'head' => 128,
|
||||
'tail' => 128,
|
||||
),
|
||||
),
|
||||
$mid_text);
|
||||
|
@ -640,7 +684,7 @@ final class HarbormasterBuildLogRenderController
|
|||
'headOffset' => $range['head'],
|
||||
'tailOffset' => $range['tail'],
|
||||
'head' => 0,
|
||||
'tail' => 4,
|
||||
'tail' => 128,
|
||||
),
|
||||
),
|
||||
$down_text);
|
||||
|
@ -727,4 +771,98 @@ final class HarbormasterBuildLogRenderController
|
|||
return phutil_tag('tr', array(), $format_cells);
|
||||
}
|
||||
|
||||
private function getHighlightViews(
|
||||
HarbormasterBuildLog $log,
|
||||
array $range,
|
||||
$log_size) {
|
||||
// If we're highlighting a line range in the file, we first need to figure
|
||||
// out the offsets for the lines we care about.
|
||||
list($range_min, $range_max) = $range;
|
||||
|
||||
// Read the markers to find a range we can load which includes both lines.
|
||||
$read_range = $log->getLineSpanningRange($range_min, $range_max);
|
||||
list($min_pos, $max_pos, $min_line) = $read_range;
|
||||
|
||||
$length = ($max_pos - $min_pos);
|
||||
|
||||
// Reject to do the read if it requires us to examine a huge amount of
|
||||
// data. For example, the user may request lines "$1-1000" of a file where
|
||||
// each line has 100MB of text.
|
||||
$limit = (1024 * 1024 * 16);
|
||||
if ($length > $limit) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$data = $log->loadData($min_pos, $length);
|
||||
|
||||
$offset = $min_pos;
|
||||
$min_offset = null;
|
||||
$max_offset = null;
|
||||
|
||||
$lines = $this->getLines($data);
|
||||
$number = ($min_line + 1);
|
||||
|
||||
foreach ($lines as $line) {
|
||||
if ($min_offset === null) {
|
||||
if ($number === $range_min) {
|
||||
$min_offset = $offset;
|
||||
}
|
||||
}
|
||||
|
||||
$offset += strlen($line);
|
||||
|
||||
if ($max_offset === null) {
|
||||
if ($number === $range_max) {
|
||||
$max_offset = $offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$number += 1;
|
||||
}
|
||||
|
||||
$context_lines = 8;
|
||||
|
||||
// Build views around the beginning and ends of the respective lines. We
|
||||
// expect these views to overlap significantly in normal circumstances
|
||||
// and be merged later.
|
||||
$views = array();
|
||||
|
||||
if ($min_offset !== null) {
|
||||
$views[] = array(
|
||||
'offset' => $min_offset,
|
||||
'lines' => $context_lines + ($range_max - $range_min) - 1,
|
||||
'direction' => 1,
|
||||
'limit' => null,
|
||||
);
|
||||
if ($min_offset > 0) {
|
||||
$views[] = array(
|
||||
'offset' => $min_offset,
|
||||
'lines' => $context_lines,
|
||||
'direction' => -1,
|
||||
'limit' => null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($max_offset !== null) {
|
||||
$views[] = array(
|
||||
'offset' => $max_offset,
|
||||
'lines' => $context_lines + ($range_max - $range_min),
|
||||
'direction' => -1,
|
||||
'limit' => null,
|
||||
);
|
||||
if ($max_offset < $log_size) {
|
||||
$views[] = array(
|
||||
'offset' => $max_offset,
|
||||
'lines' => $context_lines,
|
||||
'direction' => 1,
|
||||
'limit' => null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $views;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -212,6 +212,36 @@ final class HarbormasterBuildLog
|
|||
return $parts;
|
||||
}
|
||||
|
||||
public function getLineSpanningRange($min_line, $max_line) {
|
||||
$map = $this->getLineMap();
|
||||
if (!$map) {
|
||||
throw new Exception(pht('No line map.'));
|
||||
}
|
||||
|
||||
$min_pos = 0;
|
||||
$min_line = 0;
|
||||
$max_pos = $this->getByteLength();
|
||||
list($map) = $map;
|
||||
foreach ($map as $marker) {
|
||||
list($offset, $count) = $marker;
|
||||
|
||||
if ($count < $min_line) {
|
||||
if ($offset > $min_pos) {
|
||||
$min_pos = $offset;
|
||||
$min_line = $count;
|
||||
}
|
||||
}
|
||||
|
||||
if ($count > $max_line) {
|
||||
$max_pos = min($max_pos, $offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return array($min_pos, $max_pos, $min_line);
|
||||
}
|
||||
|
||||
|
||||
public function getReadPosition($read_offset) {
|
||||
$position = array(0, 0);
|
||||
|
||||
|
|
|
@ -67,7 +67,8 @@ final class HarbormasterBuildLogView extends AphrontView {
|
|||
'harbormaster-log',
|
||||
array(
|
||||
'contentNodeID' => $content_id,
|
||||
'renderURI' => $log->getRenderURI($this->getHighlightedLineRange()),
|
||||
'initialURI' => $log->getRenderURI($this->getHighlightedLineRange()),
|
||||
'renderURI' => $log->getRenderURI(null),
|
||||
));
|
||||
|
||||
$box_view->appendChild($content_div);
|
||||
|
|
|
@ -79,7 +79,7 @@ JX.behavior('harbormaster-log', function(config) {
|
|||
JX.DOM.setContent(contentNode, JX.$H(r.markup));
|
||||
}
|
||||
|
||||
var uri = new JX.URI(config.renderURI);
|
||||
var uri = new JX.URI(config.initialURI);
|
||||
|
||||
new JX.Request(uri, onresponse)
|
||||
.send();
|
||||
|
|
Loading…
Reference in a new issue