#!/usr/bin/env python3 import sys, argparse, subprocess, json TWEAK_NAME = { 'asm': 'asm_roll', 'ASM': 'asm_roll', 'hardlink_special': 'hardlink_specials', 'protect_args': 'secluded_args', 'protected_args': 'secluded_args', 'SIMD': 'SIMD_roll', } MOVE_OPTIM = set('asm_roll SIMD_roll'.split()) def main(): if not args.rsync or args.rsync == '-': ver_out = sys.stdin.read().strip() else: ver_out = subprocess.check_output([args.rsync, '--version', '--version'], encoding='utf-8').strip() if ver_out.startswith('{'): print(ver_out) return info = { } misplaced_optims = { } for line in ver_out.splitlines(): if line.startswith('rsync '): prog, vstr, ver, pstr, vstr2, proto = line.split() info['program'] = prog if ver.startswith('v'): ver = ver[1:] info[vstr] = ver if '.' not in proto: proto += '.0' else: proto = proto.replace('.PR', '.') info[pstr] = proto elif line.startswith('Copyright '): info['copyright'] = line[10:] elif line.startswith('Web site: '): info['url'] = line[10:] elif line.startswith(' '): if not saw_comma and ',' in line: saw_comma = True info[sect_name] = { } if saw_comma: for x in line.strip(' ,').split(', '): if ' ' in x: val, var = x.split(' ', 1) if val == 'no': val = False elif val.endswith('-bit'): var = var[:-1] + '_bits' val = int(val.split('-')[0]) else: var = x val = True var = var.replace(' ', '_').replace('-', '_') if var in TWEAK_NAME: var = TWEAK_NAME[var] if sect_name[0] != 'o' and var in MOVE_OPTIM: misplaced_optims[var] = val else: info[sect_name][var] = val else: info[sect_name] += [ x for x in line.split() if not x.startswith('(') ] elif line == '': break else: sect_name = line.strip(' :').replace(' ', '_').lower() info[sect_name] = [ ] saw_comma = False for chk in 'capabilities optimizations'.split(): if chk not in info: info[chk] = { } if misplaced_optims: info['optimizations'].update(misplaced_optims) for chk in 'checksum_list compress_list daemon_auth_list'.split(): if chk not in info: info[chk] = [ ] info['license'] = 'GPLv3' if ver[0] == '3' else 'GPLv2' info['caveat'] = 'rsync comes with ABSOLUTELY NO WARRANTY' print(json.dumps(info)) if __name__ == '__main__': parser = argparse.ArgumentParser(description="Output rsync's version data in JSON format, even if the rsync doesn't support a native json-output method.", add_help=False) parser.add_argument('rsync', nargs='?', help="Specify an rsync command to run. Otherwise stdin is consumed.") parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.") args = parser.parse_args() main() # vim: sw=4 et