b01e1e49560203943c575966f07e1515e6f5bad9
[rsync.git] / support / json-rsync-version
1 #!/usr/bin/env python3
2
3 import sys, argparse, subprocess, json
4
5 TWEAK_NAME = {
6         'asm': 'asm_roll',
7         'ASM': 'asm_roll',
8         'hardlink_special': 'hardlink_specials',
9         'protect_args': 'secluded_args',
10         'protected_args': 'secluded_args',
11         'SIMD': 'SIMD_roll',
12     }
13
14 MOVE_OPTIM = set('asm_roll SIMD_roll'.split())
15
16 def main():
17     if not args.rsync or args.rsync == '-':
18         ver_out = sys.stdin.read().strip()
19     else:
20         ver_out = subprocess.check_output([args.rsync, '--version', '--version'], encoding='utf-8').strip()
21     if ver_out.startswith('{'):
22         print(ver_out)
23         return
24     info = { }
25     misplaced_optims = { }
26     for line in ver_out.splitlines():
27         if line.startswith('rsync '):
28             prog, vstr, ver, pstr, vstr2, proto = line.split()
29             info['program'] = prog
30             if ver.startswith('v'):
31                 ver = ver[1:]
32             info[vstr] = ver
33             if '.' not in proto:
34                 proto += '.0'
35             else:
36                 proto = proto.replace('.PR', '.')
37             info[pstr] = proto
38         elif line.startswith('Copyright '):
39             info['copyright'] = line[10:]
40         elif line.startswith('Web site: '):
41             info['url'] = line[10:]
42         elif line.startswith('  '):
43             if not saw_comma and ',' in line:
44                 saw_comma = True
45                 info[sect_name] = { }
46             if saw_comma:
47                 for x in line.strip(' ,').split(', '):
48                     if ' ' in x:
49                         val, var = x.split(' ', 1)
50                         if val == 'no':
51                             val = False
52                         elif val.endswith('-bit'):
53                             var = var[:-1] + '_bits'
54                             val = int(val.split('-')[0])
55                     else:
56                         var = x
57                         val = True
58                     var = var.replace(' ', '_').replace('-', '_')
59                     if var in TWEAK_NAME:
60                         var = TWEAK_NAME[var]
61                     if sect_name[0] != 'o' and var in MOVE_OPTIM:
62                         misplaced_optims[var] = val
63                     else:
64                         info[sect_name][var] = val
65             else:
66                 info[sect_name] += [ x for x in line.split() if not x.startswith('(') ]
67         elif line == '':
68             break
69         else:
70             sect_name = line.strip(' :').replace(' ', '_').lower()
71             info[sect_name] = [ ]
72             saw_comma = False
73     for chk in 'capabilities optimizations'.split():
74         if chk not in info:
75             info[chk] = { }
76     if misplaced_optims:
77         info['optimizations'].update(misplaced_optims)
78     for chk in 'checksum_list compress_list daemon_auth_list'.split():
79         if chk not in info:
80             info[chk] = [ ]
81     info['license'] = 'GPLv3' if ver[0] == '3' else 'GPLv2'
82     info['caveat'] = 'rsync comes with ABSOLUTELY NO WARRANTY'
83     print(json.dumps(info))
84
85
86 if __name__ == '__main__':
87     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)
88     parser.add_argument('rsync', nargs='?', help="Specify an rsync command to run. Otherwise stdin is consumed.")
89     parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
90     args = parser.parse_args()
91     main()
92
93 # vim: sw=4 et