More tweaks for Actions.
[rsync.git] / packaging / cull-options
1 #!/usr/bin/env python3
2 # This script outputs either perl or python code that parses all possible options
3 # that the code in options.c might send to the server.  The resulting code is then
4 # included in the rrsync script.
5
6 import re, argparse
7
8 short_no_arg = { }
9 short_with_num = { '@': 1 }
10 long_opts = { # These include some extra long-args that BackupPC uses:
11         'block-size': 1,
12         'daemon': -1,
13         'debug': 1,
14         'fake-super': 0,
15         'fuzzy': 0,
16         'group': 0,
17         'hard-links': 0,
18         'ignore-times': 0,
19         'info': 1,
20         'links': 0,
21         'log-file': 3,
22         'munge-links': 0,
23         'no-munge-links': -1,
24         'one-file-system': 0,
25         'owner': 0,
26         'perms': 0,
27         'recursive': 0,
28         'stderr': 1,
29         'times': 0,
30         'copy-devices': -1,
31         'write-devices': -1,
32         }
33
34 def main():
35     last_long_opt = None
36
37     with open('../options.c') as fh:
38         for line in fh:
39             m = re.search(r"argstr\[x\+\+\] = '([^.ie])'", line)
40             if m:
41                 short_no_arg[m.group(1)] = 1
42                 last_long_opt = None
43                 continue
44
45             m = re.search(r'asprintf\([^,]+, "-([a-zA-Z0-9])\%l?[ud]"', line)
46             if m:
47                 short_with_num[m.group(1)] = 1
48                 last_long_opt = None
49                 continue
50
51             m = re.search(r'args\[ac\+\+\] = "--([^"=]+)"', line)
52             if m:
53                 last_long_opt = m.group(1)
54                 if last_long_opt not in long_opts:
55                     long_opts[last_long_opt] = 0
56                 else:
57                     last_long_opt = None
58                 continue
59
60             if last_long_opt:
61                 m = re.search(r'args\[ac\+\+\] = safe_arg\("", ([^[("\s]+)\);', line)
62                 if m:
63                     long_opts[last_long_opt] = 2
64                     last_long_opt = None
65                     continue
66                 if 'args[ac++] = ' in line:
67                     last_long_opt = None
68
69             m = re.search(r'return "--([^"]+-dest)";', line)
70             if m:
71                 long_opts[m.group(1)] = 2
72                 last_long_opt = None
73                 continue
74
75             m = re.search(r'asprintf\([^,]+, "--([^"=]+)=', line)
76             if not m:
77                 m = re.search(r'args\[ac\+\+\] = "--([^"=]+)=', line)
78                 if not m:
79                     m = re.search(r'args\[ac\+\+\] = safe_arg\("--([^"=]+)"', line)
80                     if not m:
81                         m = re.search(r'fmt = .*: "--([^"=]+)=', line)
82             if m:
83                 long_opts[m.group(1)] = 1
84                 last_long_opt = None
85
86     long_opts['files-from'] = 3
87
88     txt = """\
89 ### START of options data produced by the cull-options script. ###
90
91 # To disable a short-named option, add its letter to this string:
92 """
93
94     txt += str_assign('short_disabled', 's') + "\n"
95     txt += '# These are also disabled when the restricted dir is not "/":\n'
96     txt += str_assign('short_disabled_subdir', 'KLk') + "\n"
97     txt += '# These are all possible short options that we will accept (when not disabled above):\n'
98     txt += str_assign('short_no_arg', ''.join(sorted(short_no_arg)), 'DO NOT REMOVE ANY')
99     txt += str_assign('short_with_num', ''.join(sorted(short_with_num)), 'DO NOT REMOVE ANY')
100    
101     txt += """
102 # To disable a long-named option, change its value to a -1.  The values mean:
103 # 0 = the option has no arg; 1 = the arg doesn't need any checking; 2 = only
104 # check the arg when receiving; and 3 = always check the arg.
105 """
106
107     print(txt, end='')
108
109     if args.python:
110         print("long_opts = {")
111         sep = ':'
112     else:
113         print("our %long_opt = (")
114         sep = ' =>'
115
116     for opt in sorted(long_opts):
117         if opt.startswith(('min-', 'max-')):
118             val = 1
119         else:
120             val = long_opts[opt]
121         print(' ', repr(opt) + sep, str(val) + ',')
122
123     if args.python:
124         print("}")
125     else:
126         print(");")
127     print("\n### END of options data produced by the cull-options script. ###")
128
129
130 def str_assign(name, val, comment=None):
131     comment = ' # ' + comment if comment else ''
132     if args.python:
133         return name + ' = ' + repr(val) + comment + "\n"
134     return 'our $' + name + ' = ' + repr(val) + ';' + comment + "\n"
135
136
137 if __name__ == '__main__':
138     parser = argparse.ArgumentParser(description="Output culled rsync options for rrsync.", add_help=False)
139     out_group = parser.add_mutually_exclusive_group()
140     out_group.add_argument('--perl', action='store_true', help="Output perl code.")
141     out_group.add_argument('--python', action='store_true', help="Output python code (the default).")
142     parser.add_argument('--help', '-h', action='help', help="Output this help message and exit.")
143     args = parser.parse_args()
144     if not args.perl:
145         args.python = True
146     main()
147
148 # vim: sw=4 et