Page MenuHomePhabricator

D19163.diff
No OneTemporary

D19163.diff

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

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)

Event Timeline