mirror of
https://github.com/kellyjonbrazil/jc.git
synced 2025-06-17 00:07:37 +02:00
add simple summary support to rsync and rsync-s parsers
This commit is contained in:
@ -159,4 +159,4 @@ Compatibility: linux, darwin, freebsd
|
|||||||
|
|
||||||
Source: [`jc/parsers/rsync.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/rsync.py)
|
Source: [`jc/parsers/rsync.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/rsync.py)
|
||||||
|
|
||||||
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||||
|
@ -116,4 +116,4 @@ Compatibility: linux, darwin, freebsd
|
|||||||
|
|
||||||
Source: [`jc/parsers/rsync_s.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/rsync_s.py)
|
Source: [`jc/parsers/rsync_s.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/rsync_s.py)
|
||||||
|
|
||||||
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||||
|
@ -131,13 +131,13 @@ Examples:
|
|||||||
"""
|
"""
|
||||||
import re
|
import re
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from typing import List, Dict
|
from typing import List, Dict, Union
|
||||||
import jc.utils
|
import jc.utils
|
||||||
|
|
||||||
|
|
||||||
class info():
|
class info():
|
||||||
"""Provides parser metadata (version, author, etc.)"""
|
"""Provides parser metadata (version, author, etc.)"""
|
||||||
version = '1.1'
|
version = '1.2'
|
||||||
description = '`rsync` command parser'
|
description = '`rsync` command parser'
|
||||||
author = 'Kelly Brazil'
|
author = 'Kelly Brazil'
|
||||||
author_email = 'kellyjonbrazil@gmail.com'
|
author_email = 'kellyjonbrazil@gmail.com'
|
||||||
@ -171,10 +171,26 @@ def _process(proc_data: List[Dict]) -> List[Dict]:
|
|||||||
for item in proc_data:
|
for item in proc_data:
|
||||||
for key in item['summary']:
|
for key in item['summary']:
|
||||||
if key in int_list:
|
if key in int_list:
|
||||||
item['summary'][key] = jc.utils.convert_to_int(item['summary'][key])
|
item['summary'][key] = jc.utils.convert_size_to_int(item['summary'][key])
|
||||||
|
|
||||||
if key in float_list:
|
if key in float_list:
|
||||||
item['summary'][key] = jc.utils.convert_to_float(item['summary'][key])
|
converted_val: Union[float, None] = None
|
||||||
|
val = item['summary'][key]
|
||||||
|
if any([
|
||||||
|
'K' in val,
|
||||||
|
'M' in val,
|
||||||
|
'G' in val,
|
||||||
|
'T' in val
|
||||||
|
]):
|
||||||
|
converted_int_val = jc.utils.convert_size_to_int(val)
|
||||||
|
|
||||||
|
if not converted_int_val is None:
|
||||||
|
converted_val = float(converted_int_val)
|
||||||
|
|
||||||
|
else:
|
||||||
|
converted_val = jc.utils.convert_to_float(val)
|
||||||
|
|
||||||
|
item['summary'][key] = converted_val
|
||||||
|
|
||||||
for entry in item['files']:
|
for entry in item['files']:
|
||||||
for key in entry:
|
for key in entry:
|
||||||
@ -311,6 +327,9 @@ def parse(
|
|||||||
stat1_line_re = re.compile(r'(sent)\s+(?P<sent>[0-9,]+)\s+(bytes)\s+(received)\s+(?P<received>[0-9,]+)\s+(bytes)\s+(?P<bytes_sec>[0-9,.]+)\s+(bytes/sec)')
|
stat1_line_re = re.compile(r'(sent)\s+(?P<sent>[0-9,]+)\s+(bytes)\s+(received)\s+(?P<received>[0-9,]+)\s+(bytes)\s+(?P<bytes_sec>[0-9,.]+)\s+(bytes/sec)')
|
||||||
stat2_line_re = re.compile(r'(total size is)\s+(?P<total_size>[0-9,]+)\s+(speedup is)\s+(?P<speedup>[0-9,.]+)')
|
stat2_line_re = re.compile(r'(total size is)\s+(?P<total_size>[0-9,]+)\s+(speedup is)\s+(?P<speedup>[0-9,.]+)')
|
||||||
|
|
||||||
|
stat1_line_simple_re = re.compile(r'(sent)\s+(?P<sent>[0-9,.TGMK]+)\s+(bytes)\s+(received)\s+(?P<received>[0-9,.TGMK]+)\s+(bytes)\s+(?P<bytes_sec>[0-9,.TGMK]+)\s+(bytes/sec)')
|
||||||
|
stat2_line_simple_re = re.compile(r'(total\s+size\s+is)\s+(?P<total_size>[0-9,.TGMK]+)\s+(speedup\s+is)\s+(?P<speedup>[0-9,.TGMK]+)')
|
||||||
|
|
||||||
file_line_log_re = re.compile(r'(?P<date>\d\d\d\d/\d\d/\d\d)\s+(?P<time>\d\d:\d\d:\d\d)\s+\[(?P<process>\d+)\]\s+(?P<meta>[<>ch.*][fdlDS][c.+ ?][s.+ ?][t.+ ?][p.+ ?][o.+ ?][g.+ ?][u.+ ?][a.+ ?][x.+ ?]) (?P<name>.+)')
|
file_line_log_re = re.compile(r'(?P<date>\d\d\d\d/\d\d/\d\d)\s+(?P<time>\d\d:\d\d:\d\d)\s+\[(?P<process>\d+)\]\s+(?P<meta>[<>ch.*][fdlDS][c.+ ?][s.+ ?][t.+ ?][p.+ ?][o.+ ?][g.+ ?][u.+ ?][a.+ ?][x.+ ?]) (?P<name>.+)')
|
||||||
file_line_log_mac_re = re.compile(r'(?P<date>\d\d\d\d/\d\d/\d\d)\s+(?P<time>\d\d:\d\d:\d\d)\s+\[(?P<process>\d+)\]\s+(?P<meta>[<>ch.*][fdlDS][c.+ ?][s.+ ?][t.+ ?][p.+ ?][o.+ ?][g.+ ?][x.+ ?]) (?P<name>.+)')
|
file_line_log_mac_re = re.compile(r'(?P<date>\d\d\d\d/\d\d/\d\d)\s+(?P<time>\d\d:\d\d:\d\d)\s+\[(?P<process>\d+)\]\s+(?P<meta>[<>ch.*][fdlDS][c.+ ?][s.+ ?][t.+ ?][p.+ ?][o.+ ?][g.+ ?][x.+ ?]) (?P<name>.+)')
|
||||||
stat_line_log_re = re.compile(r'(?P<date>\d\d\d\d/\d\d/\d\d)\s+(?P<time>\d\d:\d\d:\d\d)\s+\[(?P<process>\d+)\]\s+sent\s+(?P<sent>[\d,]+)\s+bytes\s+received\s+(?P<received>[\d,]+)\s+bytes\s+total\s+size\s+(?P<total_size>[\d,]+)')
|
stat_line_log_re = re.compile(r'(?P<date>\d\d\d\d/\d\d/\d\d)\s+(?P<time>\d\d:\d\d:\d\d)\s+\[(?P<process>\d+)\]\s+sent\s+(?P<sent>[\d,]+)\s+bytes\s+received\s+(?P<received>[\d,]+)\s+bytes\s+total\s+size\s+(?P<total_size>[\d,]+)')
|
||||||
@ -445,6 +464,21 @@ def parse(
|
|||||||
rsync_run['summary']['speedup'] = stat2_line.group('speedup')
|
rsync_run['summary']['speedup'] = stat2_line.group('speedup')
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
stat1_line_simple = stat1_line_simple_re.match(line)
|
||||||
|
if stat1_line_simple:
|
||||||
|
rsync_run['summary'] = {
|
||||||
|
'sent': stat1_line_simple.group('sent'),
|
||||||
|
'received': stat1_line_simple.group('received'),
|
||||||
|
'bytes_sec': stat1_line_simple.group('bytes_sec')
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
|
||||||
|
stat2_line_simple = stat2_line_simple_re.match(line)
|
||||||
|
if stat2_line_simple:
|
||||||
|
rsync_run['summary']['total_size'] = stat2_line_simple.group('total_size')
|
||||||
|
rsync_run['summary']['speedup'] = stat2_line_simple.group('speedup')
|
||||||
|
continue
|
||||||
|
|
||||||
stat_line_log = stat_line_log_re.match(line)
|
stat_line_log = stat_line_log_re.match(line)
|
||||||
if stat_line_log:
|
if stat_line_log:
|
||||||
rsync_run['summary'] = {
|
rsync_run['summary'] = {
|
||||||
|
@ -88,7 +88,7 @@ from jc.streaming import (
|
|||||||
|
|
||||||
class info():
|
class info():
|
||||||
"""Provides parser metadata (version, author, etc.)"""
|
"""Provides parser metadata (version, author, etc.)"""
|
||||||
version = '1.2'
|
version = '1.3'
|
||||||
description = '`rsync` command streaming parser'
|
description = '`rsync` command streaming parser'
|
||||||
author = 'Kelly Brazil'
|
author = 'Kelly Brazil'
|
||||||
author_email = 'kellyjonbrazil@gmail.com'
|
author_email = 'kellyjonbrazil@gmail.com'
|
||||||
@ -121,10 +121,26 @@ def _process(proc_data: Dict) -> Dict:
|
|||||||
|
|
||||||
for key in proc_data.copy():
|
for key in proc_data.copy():
|
||||||
if key in int_list:
|
if key in int_list:
|
||||||
proc_data[key] = jc.utils.convert_to_int(proc_data[key])
|
proc_data[key] = jc.utils.convert_size_to_int(proc_data[key])
|
||||||
|
|
||||||
if key in float_list:
|
if key in float_list:
|
||||||
proc_data[key] = jc.utils.convert_to_float(proc_data[key])
|
converted_val: Union[float, None] = None
|
||||||
|
val = proc_data[key]
|
||||||
|
if any([
|
||||||
|
'K' in val,
|
||||||
|
'M' in val,
|
||||||
|
'G' in val,
|
||||||
|
'T' in val
|
||||||
|
]):
|
||||||
|
converted_int_val = jc.utils.convert_size_to_int(val)
|
||||||
|
|
||||||
|
if not converted_int_val is None:
|
||||||
|
converted_val = float(converted_int_val)
|
||||||
|
|
||||||
|
else:
|
||||||
|
converted_val = jc.utils.convert_to_float(val)
|
||||||
|
|
||||||
|
proc_data[key] = converted_val
|
||||||
|
|
||||||
# add timestamp
|
# add timestamp
|
||||||
if 'date' in proc_data and 'time' in proc_data:
|
if 'date' in proc_data and 'time' in proc_data:
|
||||||
@ -254,6 +270,9 @@ def parse(
|
|||||||
stat1_line_re = re.compile(r'(sent)\s+(?P<sent>[0-9,]+)\s+(bytes)\s+(received)\s+(?P<received>[0-9,]+)\s+(bytes)\s+(?P<bytes_sec>[0-9,.]+)\s+(bytes/sec)')
|
stat1_line_re = re.compile(r'(sent)\s+(?P<sent>[0-9,]+)\s+(bytes)\s+(received)\s+(?P<received>[0-9,]+)\s+(bytes)\s+(?P<bytes_sec>[0-9,.]+)\s+(bytes/sec)')
|
||||||
stat2_line_re = re.compile(r'(total size is)\s+(?P<total_size>[0-9,]+)\s+(speedup is)\s+(?P<speedup>[0-9,.]+)')
|
stat2_line_re = re.compile(r'(total size is)\s+(?P<total_size>[0-9,]+)\s+(speedup is)\s+(?P<speedup>[0-9,.]+)')
|
||||||
|
|
||||||
|
stat1_line_simple_re = re.compile(r'(sent)\s+(?P<sent>[0-9,.TGMK]+)\s+(bytes)\s+(received)\s+(?P<received>[0-9,.TGMK]+)\s+(bytes)\s+(?P<bytes_sec>[0-9,.TGMK]+)\s+(bytes/sec)')
|
||||||
|
stat2_line_simple_re = re.compile(r'(total\s+size\s+is)\s+(?P<total_size>[0-9,.TGMK]+)\s+(speedup\s+is)\s+(?P<speedup>[0-9,.TGMK]+)')
|
||||||
|
|
||||||
file_line_log_re = re.compile(r'(?P<date>\d\d\d\d/\d\d/\d\d)\s+(?P<time>\d\d:\d\d:\d\d)\s+\[(?P<process>\d+)\]\s+(?P<meta>[<>ch.*][fdlDS][c.+ ?][s.+ ?][t.+ ?][p.+ ?][o.+ ?][g.+ ?][u.+ ?][a.+ ?][x.+ ?]) (?P<name>.+)')
|
file_line_log_re = re.compile(r'(?P<date>\d\d\d\d/\d\d/\d\d)\s+(?P<time>\d\d:\d\d:\d\d)\s+\[(?P<process>\d+)\]\s+(?P<meta>[<>ch.*][fdlDS][c.+ ?][s.+ ?][t.+ ?][p.+ ?][o.+ ?][g.+ ?][u.+ ?][a.+ ?][x.+ ?]) (?P<name>.+)')
|
||||||
file_line_log_mac_re = re.compile(r'(?P<date>\d\d\d\d/\d\d/\d\d)\s+(?P<time>\d\d:\d\d:\d\d)\s+\[(?P<process>\d+)\]\s+(?P<meta>[<>ch.*][fdlDS][c.+ ?][s.+ ?][t.+ ?][p.+ ?][o.+ ?][g.+ ?][x.+ ?]) (?P<name>.+)')
|
file_line_log_mac_re = re.compile(r'(?P<date>\d\d\d\d/\d\d/\d\d)\s+(?P<time>\d\d:\d\d:\d\d)\s+\[(?P<process>\d+)\]\s+(?P<meta>[<>ch.*][fdlDS][c.+ ?][s.+ ?][t.+ ?][p.+ ?][o.+ ?][g.+ ?][x.+ ?]) (?P<name>.+)')
|
||||||
stat_line_log_re = re.compile(r'(?P<date>\d\d\d\d/\d\d/\d\d)\s+(?P<time>\d\d:\d\d:\d\d)\s+\[(?P<process>\d+)\]\s+sent\s+(?P<sent>[\d,]+)\s+bytes\s+received\s+(?P<received>[\d,]+)\s+bytes\s+total\s+size\s+(?P<total_size>[\d,]+)')
|
stat_line_log_re = re.compile(r'(?P<date>\d\d\d\d/\d\d/\d\d)\s+(?P<time>\d\d:\d\d:\d\d)\s+\[(?P<process>\d+)\]\s+sent\s+(?P<sent>[\d,]+)\s+bytes\s+received\s+(?P<received>[\d,]+)\s+bytes\s+total\s+size\s+(?P<total_size>[\d,]+)')
|
||||||
@ -403,6 +422,22 @@ def parse(
|
|||||||
summary['speedup'] = stat2_line.group('speedup')
|
summary['speedup'] = stat2_line.group('speedup')
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
stat1_line_simple = stat1_line_simple_re.match(line)
|
||||||
|
if stat1_line_simple:
|
||||||
|
summary = {
|
||||||
|
'type': 'summary',
|
||||||
|
'sent': stat1_line_simple.group('sent'),
|
||||||
|
'received': stat1_line_simple.group('received'),
|
||||||
|
'bytes_sec': stat1_line_simple.group('bytes_sec')
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
|
||||||
|
stat2_line_simple = stat2_line_simple_re.match(line)
|
||||||
|
if stat2_line_simple:
|
||||||
|
summary['total_size'] = stat2_line_simple.group('total_size')
|
||||||
|
summary['speedup'] = stat2_line_simple.group('speedup')
|
||||||
|
continue
|
||||||
|
|
||||||
stat_line_log = stat_line_log_re.match(line)
|
stat_line_log = stat_line_log_re.match(line)
|
||||||
if stat_line_log:
|
if stat_line_log:
|
||||||
summary = {
|
summary = {
|
||||||
|
@ -401,6 +401,9 @@ def convert_size_to_int(size: str, binary: bool = False) -> Optional[int]:
|
|||||||
>>> convert_size_to_int('1.5 GB', binary=True)
|
>>> convert_size_to_int('1.5 GB', binary=True)
|
||||||
1610612736
|
1610612736
|
||||||
"""
|
"""
|
||||||
|
# normalize input by removing commas
|
||||||
|
size = size.replace(',', '')
|
||||||
|
|
||||||
def tokenize(text: str) -> List[str]:
|
def tokenize(text: str) -> List[str]:
|
||||||
tokenized_input: List = []
|
tokenized_input: List = []
|
||||||
for token in re.split(r'(\d+(?:\.\d+)?)', text):
|
for token in re.split(r'(\d+(?:\.\d+)?)', text):
|
||||||
|
2
man/jc.1
2
man/jc.1
@ -1,4 +1,4 @@
|
|||||||
.TH jc 1 2024-02-26 1.25.2 "JSON Convert"
|
.TH jc 1 2024-02-27 1.25.2 "JSON Convert"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
\fBjc\fP \- JSON Convert JSONifies the output of many CLI tools, file-types,
|
\fBjc\fP \- JSON Convert JSONifies the output of many CLI tools, file-types,
|
||||||
and strings
|
and strings
|
||||||
|
@ -161,6 +161,18 @@ class MyTests(unittest.TestCase):
|
|||||||
"""
|
"""
|
||||||
self.assertEqual(jc.parsers.rsync.parse(self.osx_10_14_6_rsync_i_vvv_logfile_nochange, quiet=True), self.osx_10_14_6_rsync_i_vvv_logfile_nochange_json)
|
self.assertEqual(jc.parsers.rsync.parse(self.osx_10_14_6_rsync_i_vvv_logfile_nochange, quiet=True), self.osx_10_14_6_rsync_i_vvv_logfile_nochange_json)
|
||||||
|
|
||||||
|
def test_rsync_simple_summary(self):
|
||||||
|
"""
|
||||||
|
Test 'rsync avh' output with a simple summary
|
||||||
|
"""
|
||||||
|
data = '''sending incremental file list
|
||||||
|
|
||||||
|
sent 8.71M bytes received 29.88K bytes 10.99K bytes/sec
|
||||||
|
total size is 221.79G speedup is 25,388.23
|
||||||
|
'''
|
||||||
|
expected = [{"summary":{"sent":8710000,"received":29880,"bytes_sec":10990.0,"total_size":221790000000,"speedup":25388.23},"files":[]}]
|
||||||
|
self.assertEqual(jc.parsers.rsync.parse(data, quiet=True), expected)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -172,6 +172,18 @@ class MyTests(unittest.TestCase):
|
|||||||
"""
|
"""
|
||||||
self.assertEqual(list(jc.parsers.rsync_s.parse(self.osx_10_14_6_rsync_i_vvv_logfile_nochange.splitlines(), quiet=True)), self.osx_10_14_6_rsync_i_vvv_logfile_nochange_streaming_json)
|
self.assertEqual(list(jc.parsers.rsync_s.parse(self.osx_10_14_6_rsync_i_vvv_logfile_nochange.splitlines(), quiet=True)), self.osx_10_14_6_rsync_i_vvv_logfile_nochange_streaming_json)
|
||||||
|
|
||||||
|
def test_rsync_s_simple_summary(self):
|
||||||
|
"""
|
||||||
|
Test 'rsync avh' output with a simple summary
|
||||||
|
"""
|
||||||
|
data = '''sending incremental file list
|
||||||
|
|
||||||
|
sent 8.71M bytes received 29.88K bytes 10.99K bytes/sec
|
||||||
|
total size is 221.79G speedup is 25,388.23
|
||||||
|
'''
|
||||||
|
expected = [{"type":"summary","sent":8710000,"received":29880,"bytes_sec":10990.0,"total_size":221790000000,"speedup":25388.23}]
|
||||||
|
self.assertEqual(list(jc.parsers.rsync_s.parse(data.splitlines(), quiet=True)), expected)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
Reference in New Issue
Block a user