#!/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
