Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14111968
D19163.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
11 KB
Referenced Files
None
Subscribers
None
D19163.diff
View Options
diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -416,7 +416,7 @@
'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 @@
'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 @@
'javelin-behavior',
'javelin-quicksand',
),
- '796a8803' => array(
- 'javelin-behavior',
- ),
'7a68dda3' => array(
'owners-path-editor',
'javelin-behavior',
@@ -1768,6 +1765,9 @@
'javelin-util',
'phabricator-prefab',
),
+ 'ab1173d1' => array(
+ 'javelin-behavior',
+ ),
'ab2f381b' => array(
'javelin-request',
'javelin-behavior',
diff --git a/src/applications/harbormaster/controller/HarbormasterBuildLogRenderController.php b/src/applications/harbormaster/controller/HarbormasterBuildLogRenderController.php
--- a/src/applications/harbormaster/controller/HarbormasterBuildLogRenderController.php
+++ b/src/applications/harbormaster/controller/HarbormasterBuildLogRenderController.php
@@ -16,6 +16,8 @@
return new Aphront404Response();
}
+ $highlight_range = $request->getURILineRange('lines', 1000);
+
$log_size = $this->getTotalByteLength($log);
$head_lines = $request->getInt('head');
@@ -65,6 +67,16 @@
);
}
+ 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 @@
$direction = $read['direction'];
if ($direction < 0) {
- $offset -= $read_length;
- if ($offset < 0) {
+ if ($offset > $read_length) {
+ $offset -= $read_length;
+ } else {
+ $read_length = $offset;
$offset = 0;
- $read_length = $log_size;
}
}
@@ -215,8 +228,10 @@
}
$limit = $view['limit'];
- if ($limit < ($view_offset + $view_length)) {
- $view_length = ($limit - $view_offset);
+ if ($limit !== null) {
+ if ($limit < ($view_offset + $view_length)) {
+ $view_length = ($limit - $view_offset);
+ }
}
} else {
$view_offset = $data_offset;
@@ -226,9 +241,11 @@
}
$limit = $view['limit'];
- if ($limit > $view_offset) {
- $view_length -= ($limit - $view_offset);
- $view_offset = $limit;
+ if ($limit !== null) {
+ if ($limit > $view_offset) {
+ $view_length -= ($limit - $view_offset);
+ $view_offset = $limit;
+ }
}
}
@@ -325,7 +342,6 @@
}
$uri = $log->getURI();
- $highlight_range = $request->getURIData('lines');
$rows = array();
foreach ($render as $range) {
@@ -339,6 +355,16 @@
$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 @@
$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 @@
$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) {
- $views[$ukey] = array(
- 'sliceLength' => ($vse - $uss),
- 'viewLength' => ($ve - $us),
- ) + $views[$ukey];
-
- unset($views[$vkey]);
- continue;
- }
- }
+ // 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(
+ 'viewOffset' => $offset,
+ 'viewLength' => $length,
+ 'sliceOffset' => $slice_offset,
+ 'sliceLength' => $slice_length,
+ ) + $views[$ukey];
+
+ unset($views[$vkey]);
}
}
@@ -603,7 +647,7 @@
'meta' => array(
'headOffset' => $range['head'],
'tailOffset' => $range['tail'],
- 'head' => 4,
+ 'head' => 128,
'tail' => 0,
),
),
@@ -620,8 +664,8 @@
'meta' => array(
'headOffset' => $range['head'],
'tailOffset' => $range['tail'],
- 'head' => 2,
- 'tail' => 2,
+ 'head' => 128,
+ 'tail' => 128,
),
),
$mid_text);
@@ -640,7 +684,7 @@
'headOffset' => $range['head'],
'tailOffset' => $range['tail'],
'head' => 0,
- 'tail' => 4,
+ 'tail' => 128,
),
),
$down_text);
@@ -727,4 +771,98 @@
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;
+ }
+
}
diff --git a/src/applications/harbormaster/storage/build/HarbormasterBuildLog.php b/src/applications/harbormaster/storage/build/HarbormasterBuildLog.php
--- a/src/applications/harbormaster/storage/build/HarbormasterBuildLog.php
+++ b/src/applications/harbormaster/storage/build/HarbormasterBuildLog.php
@@ -212,6 +212,36 @@
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);
diff --git a/src/applications/harbormaster/view/HarbormasterBuildLogView.php b/src/applications/harbormaster/view/HarbormasterBuildLogView.php
--- a/src/applications/harbormaster/view/HarbormasterBuildLogView.php
+++ b/src/applications/harbormaster/view/HarbormasterBuildLogView.php
@@ -67,7 +67,8 @@
'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);
diff --git a/webroot/rsrc/js/application/harbormaster/behavior-harbormaster-log.js b/webroot/rsrc/js/application/harbormaster/behavior-harbormaster-log.js
--- a/webroot/rsrc/js/application/harbormaster/behavior-harbormaster-log.js
+++ b/webroot/rsrc/js/application/harbormaster/behavior-harbormaster-log.js
@@ -79,7 +79,7 @@
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();
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Nov 28, 11:32 PM (13 h, 35 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6802774
Default Alt Text
D19163.diff (11 KB)
Attached To
Mode
D19163: Support rendering arbitrary sections in the middle of a Harbormaster build log so links to line 3500 work
Attached
Detach File
Event Timeline
Log In to Comment