123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- #!/usr/bin/env python3
- """ Write a python argparse object and text file for a given OptList. """
- import argparse
- _PY_BEGIN = """#!/usr/bin/env python3
- \"\"\" Arguments for the tarsnap CLI. Does nothing else.
- WARNING: options starting with "mode-" are a workaround for
- argparse not being able to have subparsers which start with a hyphen.
- https://bugs.python.org/issue34046
- For the real tarsnap options, remove any "mode-" string.
- \"\"\"
- import argparse
- def get_parser():
- \"\"\" Create a parser for tarsnap command-line arguments. \"\"\"
- parser = argparse.ArgumentParser(prog="tarsnap")
- subparsers = parser.add_subparsers()
- # Commands available for all modes.
- """
- _PY_NOARG = """ {parser_name}.add_argument("{opt}", action="store_true",
- {spaces}help="{desc}")
- """
- # Don't add "quotes" around the 'type' argument.
- _PY_ARG_TYPE = """ {parser_name}.add_argument("{opt}", metavar="{metavar}",
- {spaces}type={argtype},
- {spaces}help="{desc}")
- """
- _PY_SUBPARSER = """
- # Commands specific for mode {mode}.
- subparser = subparsers.add_parser("{mode}",
- {spaces}help="{desc}",
- {spaces}description="{desc}")
- """
- _PY_END = """ return parser
- if __name__ == "__main__":
- tarsnap_parser = get_parser()
- tarsnap_parser.parse_args()
- """
- def get_argtypestr(arg):
- """ Return the type of variable to use for the tarsnap arg as a string. """
- if arg in ["bytespercheckpoint", "bytespersecond", "X", "numbytes",
- "count"]:
- argtypestr = "int"
- elif arg in ["cache-dir", "directory"]:
- argtypestr = "directory"
- elif arg in ["filename", "key-file"]:
- argtypestr = "filename"
- elif arg in ["archive-name"]:
- argtypestr = "archive-name"
- elif arg in ["date"]:
- argtypestr = "date"
- elif arg in ["method:arg", "pattern"]:
- argtypestr = "str"
- else:
- print("Unsupported arg:", arg)
- exit(1)
- return argtypestr
- def get_argtype(arg):
- """ Return the type of variable to use for the tarsnap arg. """
- argtypestr = get_argtypestr(arg)
- if argtypestr == "str":
- argtype = str
- elif argtypestr == "int":
- argtype = int
- elif ["directory", "filename", "date",
- "archive-name"].index(argtypestr) >= 0:
- # No special handling (yet?)
- argtype = str
- else:
- print("Unsupported argtypestr:\t%s\t%s" % (arg, argtypestr))
- exit(1)
- return argtype
- def add_arg(parser_obj, parser_name, optarg):
- """ Add an optarg to the parser_obj called parser_name. """
- # Skip -h because argparse has its own -h --help.
- if optarg.opt == "-h":
- return ""
- spaces = " " * len("%s.add_argument(" % parser_name)
- text = ""
- if optarg.arg:
- argtype = get_argtype(optarg.arg)
- text = _PY_ARG_TYPE.format(parser_name=parser_name, opt=optarg.opt,
- spaces=spaces, desc=optarg.desc,
- metavar=optarg.arg,
- argtype=argtype.__name__)
- parser_obj.add_argument(optarg.opt, metavar=optarg.arg,
- help=optarg.desc,
- type=argtype)
- else:
- text = _PY_NOARG.format(parser_name=parser_name, opt=optarg.opt,
- spaces=spaces, desc=optarg.desc)
- parser_obj.add_argument(optarg.opt, action="store_true",
- help=optarg.desc)
- return text
- def is_mode_global(mode):
- """ Is this mode global? """
- if mode == "":
- return True
- modestr = mode[0]
- if modestr == "(all modes)" or modestr.startswith("(use with"):
- return True
- return False
- def add_global_options(parser_obj, parser_name, optlist):
- """ Add all global options to parser_obj. """
- relevant = optlist.get_optargs_with_func_modes(is_mode_global)
- text = ""
- for optarg in relevant:
- text += add_arg(parser_obj, parser_name, optarg)
- return text
- def generate(options, optlist, descs):
- """ Generate an argparse object and text for a python file. """
- parser = argparse.ArgumentParser(prog="tarsnap")
- subparsers = parser.add_subparsers()
- text = ""
- # Global options
- text += add_global_options(parser, "parser", optlist)
- for mode in sorted(options["modes"]):
- if len(mode) == 1:
- modestr = "mode-%s" % mode
- else:
- modestr = "mode--%s" % mode
- desc = descs.get(modestr)
- spaces = " " * len("subparser = subparsers.add_parser(")
- text += _PY_SUBPARSER.format(mode=modestr, spaces=spaces, desc=desc)
- # argparse uses "description" for the main text shown in:
- # ./tarsnap.py mode-c --help
- # and "help" for the mode-c text displayed in:
- # ./tarsnap.py --help
- subparser = subparsers.add_parser(modestr, help=desc, description=desc)
- # Add options specific to this mode.
- relevant = optlist.get_optargs_with_func_modes(
- lambda x, m=mode: m in x)
- for optarg in relevant:
- text += add_arg(subparser, "subparser", optarg)
- # Add global options (which will still be valid).
- text += add_global_options(subparser, "subparser", optlist)
- return parser, text
- def write_argparse(filename_py, options, optlist, descs):
- """ Write a python file with argparse for tarsnap.
- WARNING: options starting with "mode-" are a workaround for
- argparse not being able to have subparsers which start with a hyphen.
- https://bugs.python.org/issue34046
- """
- _, parser_text = generate(options, optlist, descs)
- # Write argparse file.
- with open(filename_py, "wt", encoding="utf-8") as fileobj:
- fileobj.write(_PY_BEGIN)
- fileobj.write(parser_text)
- fileobj.write(_PY_END)
|