mirror of
https://github.com/borgbackup/borg.git
synced 2025-03-04 10:39:50 +00:00
enhance JSON progress information
separate output types, extra information
This commit is contained in:
parent
7c9c4b61d7
commit
6288c9f751
2 changed files with 76 additions and 15 deletions
|
@ -39,6 +39,33 @@ archive_progress
|
|||
path
|
||||
Current path
|
||||
|
||||
progress_message
|
||||
A message-based progress information with no concrete progress information, just a message
|
||||
saying what is currently worked on.
|
||||
|
||||
operation
|
||||
integer ID of the operation
|
||||
finished
|
||||
boolean indicating whether the operation has finished, only the last object for an *operation*
|
||||
can have this property set to *true*.
|
||||
message
|
||||
current progress message (may be empty/absent)
|
||||
|
||||
progress_percent
|
||||
Absolute progress display with defined end/total and current value.
|
||||
|
||||
operation
|
||||
integer ID of the operation
|
||||
finished
|
||||
boolean indicating whether the operation has finished, only the last object for an *operation*
|
||||
can have this property set to *true*.
|
||||
message
|
||||
A formatted progress message, this will include the percentage and perhaps other information
|
||||
current
|
||||
Current value (always less-or-equal to *total*)
|
||||
total
|
||||
Total value
|
||||
|
||||
file_status
|
||||
This is only output by :ref:`borg_create` and :ref:`borg_recreate` if ``--list`` is specified. The usual
|
||||
rules for the file listing applies, including the ``--filter`` option.
|
||||
|
|
|
@ -1377,10 +1377,20 @@ def ellipsis_truncate(msg, space):
|
|||
|
||||
class ProgressIndicatorBase:
|
||||
LOGGER = 'borg.output.progress'
|
||||
JSON_TYPE = None
|
||||
json = False
|
||||
|
||||
operation_id_counter = 0
|
||||
|
||||
@classmethod
|
||||
def operation_id(cls):
|
||||
cls.operation_id_counter += 1
|
||||
return cls.operation_id_counter
|
||||
|
||||
def __init__(self):
|
||||
self.handler = None
|
||||
self.logger = logging.getLogger(self.LOGGER)
|
||||
self.id = self.operation_id()
|
||||
|
||||
# If there are no handlers, set one up explicitly because the
|
||||
# terminator and propagation needs to be set. If there are,
|
||||
|
@ -1394,6 +1404,7 @@ class ProgressIndicatorBase:
|
|||
try:
|
||||
formatter = logger.formatter
|
||||
terminator = '\n' if logger.json else '\r'
|
||||
self.json = logger.json
|
||||
except AttributeError:
|
||||
terminator = '\r'
|
||||
else:
|
||||
|
@ -1404,12 +1415,30 @@ class ProgressIndicatorBase:
|
|||
if self.logger.level == logging.NOTSET:
|
||||
self.logger.setLevel(logging.WARN)
|
||||
self.logger.propagate = False
|
||||
self.emit = self.logger.getEffectiveLevel() == logging.INFO
|
||||
|
||||
def __del__(self):
|
||||
if self.handler is not None:
|
||||
self.logger.removeHandler(self.handler)
|
||||
self.handler.close()
|
||||
|
||||
def output_json(self, *, finished=False, **kwargs):
|
||||
assert self.json
|
||||
if not self.emit:
|
||||
return
|
||||
print(json.dumps(dict(
|
||||
operation=self.id,
|
||||
type=self.JSON_TYPE,
|
||||
finished=finished,
|
||||
**kwargs,
|
||||
)), file=sys.stderr)
|
||||
|
||||
def finish(self):
|
||||
if self.json:
|
||||
self.output_json(finished=True)
|
||||
else:
|
||||
self.output('')
|
||||
|
||||
|
||||
def justify_to_terminal_size(message):
|
||||
terminal_space = get_terminal_size(fallback=(-1, -1))[0]
|
||||
|
@ -1420,14 +1449,18 @@ def justify_to_terminal_size(message):
|
|||
|
||||
|
||||
class ProgressIndicatorMessage(ProgressIndicatorBase):
|
||||
def output(self, msg):
|
||||
self.logger.info(justify_to_terminal_size(msg))
|
||||
JSON_TYPE = 'progress_message'
|
||||
|
||||
def finish(self):
|
||||
self.output('')
|
||||
def output(self, msg):
|
||||
if self.json:
|
||||
self.output_json(message=msg)
|
||||
else:
|
||||
self.logger.info(justify_to_terminal_size(msg))
|
||||
|
||||
|
||||
class ProgressIndicatorPercent(ProgressIndicatorBase):
|
||||
JSON_TYPE = 'progress_percent'
|
||||
|
||||
def __init__(self, total=0, step=5, start=0, msg="%3.0f%%"):
|
||||
"""
|
||||
Percentage-based progress indicator
|
||||
|
@ -1466,22 +1499,23 @@ class ProgressIndicatorPercent(ProgressIndicatorBase):
|
|||
if pct is not None:
|
||||
# truncate the last argument, if no space is available
|
||||
if info is not None:
|
||||
# no need to truncate if we're not outputing to a terminal
|
||||
terminal_space = get_terminal_size(fallback=(-1, -1))[0]
|
||||
if terminal_space != -1:
|
||||
space = terminal_space - len(self.msg % tuple([pct] + info[:-1] + ['']))
|
||||
info[-1] = ellipsis_truncate(info[-1], space)
|
||||
if not self.json:
|
||||
# no need to truncate if we're not outputing to a terminal
|
||||
terminal_space = get_terminal_size(fallback=(-1, -1))[0]
|
||||
if terminal_space != -1:
|
||||
space = terminal_space - len(self.msg % tuple([pct] + info[:-1] + ['']))
|
||||
info[-1] = ellipsis_truncate(info[-1], space)
|
||||
return self.output(self.msg % tuple([pct] + info), justify=False)
|
||||
|
||||
return self.output(self.msg % pct)
|
||||
|
||||
def output(self, message, justify=True):
|
||||
if justify:
|
||||
message = justify_to_terminal_size(message)
|
||||
self.logger.info(message)
|
||||
|
||||
def finish(self):
|
||||
self.output('')
|
||||
if self.json:
|
||||
self.output_json(message=message, current=self.counter, total=self.total)
|
||||
else:
|
||||
if justify:
|
||||
message = justify_to_terminal_size(message)
|
||||
self.logger.info(message)
|
||||
|
||||
|
||||
class ProgressIndicatorEndless:
|
||||
|
|
Loading…
Add table
Reference in a new issue