| OLD | NEW |
| 1 # Copyright 2013 The LUCI Authors. All rights reserved. | 1 # Copyright 2013 The LUCI Authors. All rights reserved. |
| 2 # Use of this source code is governed under the Apache License, Version 2.0 | 2 # Use of this source code is governed under the Apache License, Version 2.0 |
| 3 # that can be found in the LICENSE file. | 3 # that can be found in the LICENSE file. |
| 4 | 4 |
| 5 from collections import deque |
| 6 |
| 5 import contextlib | 7 import contextlib |
| 6 import datetime | 8 import datetime |
| 7 import functools | 9 import functools |
| 8 import logging | 10 import logging |
| 9 import os | 11 import os |
| 10 import sys | 12 import sys |
| 11 import traceback | 13 import traceback |
| 12 import time | 14 import time |
| 13 import urllib | 15 import urllib |
| 14 | 16 |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 302 it (iterable): An iterable to traverse. | 304 it (iterable): An iterable to traverse. |
| 303 exc_types (list): An optional list of specific exception types to defer. | 305 exc_types (list): An optional list of specific exception types to defer. |
| 304 If empty, Exception will be used. Any Exceptions not referenced by this | 306 If empty, Exception will be used. Any Exceptions not referenced by this |
| 305 list will skip deferring and be immediately raised. | 307 list will skip deferring and be immediately raised. |
| 306 """ | 308 """ |
| 307 mexc_builder = MultiException.Builder() | 309 mexc_builder = MultiException.Builder() |
| 308 for e in it: | 310 for e in it: |
| 309 with mexc_builder.catch(*exc_types): | 311 with mexc_builder.catch(*exc_types): |
| 310 fn(e) | 312 fn(e) |
| 311 mexc_builder.raise_if_any() | 313 mexc_builder.raise_if_any() |
| 314 |
| 315 |
| 316 def snip_output_lines(lines_data, max_bytes): |
| 317 """Snip the middle out of very large data file. |
| 318 |
| 319 The output will be roughly max_bytes in size with the first half of the bytes |
| 320 showing the start of the data and the second half of the bytes showing the |
| 321 end of the data. If any data was removed, an indicator of |
| 322 '...\\n<snip>\\n... ' will be placed where the removed data was like so; |
| 323 |
| 324 no more than half max_bytes |
| 325 of starting data |
| 326 <snip> |
| 327 no more than half max_bytes of |
| 328 data at the end of the file. |
| 329 |
| 330 |
| 331 Args: |
| 332 lines_data (list of strings): Lines of the file. |
| 333 max_bytes (int): Maximum amount of bytes. |
| 334 """ |
| 335 lines_deque = deque(lines_data) |
| 336 |
| 337 max_bytes = int(max_bytes / 2) |
| 338 |
| 339 start_lines = [] |
| 340 start_count = max_bytes |
| 341 while lines_deque and start_count > 0: |
| 342 line = lines_deque.popleft() |
| 343 start_data = line[:start_count] |
| 344 start_count -= len(start_data) |
| 345 if len(line) == len(start_data): |
| 346 start_lines.append(line) |
| 347 else: |
| 348 start_lines.append('%s ...' % start_data) |
| 349 lines_deque.appendleft(line[len(start_data):]) |
| 350 break |
| 351 |
| 352 end_lines = [] |
| 353 end_count = max_bytes |
| 354 while lines_deque and end_count > 0: |
| 355 line = lines_deque.pop() |
| 356 end_data = line[-end_count:] |
| 357 end_count -= len(end_data) |
| 358 if len(line) == len(end_data): |
| 359 end_lines.append(line) |
| 360 else: |
| 361 end_lines.append('... %s' % end_data) |
| 362 lines_deque.append(line[:-len(end_data)]) |
| 363 break |
| 364 |
| 365 if not lines_deque: |
| 366 return lines_data |
| 367 else: |
| 368 return start_lines + ['<snip>'] + end_lines[::-1] |
| OLD | NEW |