diff options
Diffstat (limited to 'pyanaconda/anaconda_optparse.py')
-rw-r--r-- | pyanaconda/anaconda_optparse.py | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/pyanaconda/anaconda_optparse.py b/pyanaconda/anaconda_optparse.py new file mode 100644 index 000000000..ccb0361d7 --- /dev/null +++ b/pyanaconda/anaconda_optparse.py @@ -0,0 +1,126 @@ +# +# anaconda_optparse.py: option parsing for anaconda (CLI and boot args) +# +# Copyright (C) 2012 Red Hat, Inc. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# Authors: +# Will Woods <wwoods@redhat.com> + +from flags import BootArgs +from optparse import OptionParser, OptionConflictError + +class AnacondaOptionParser(OptionParser): + """ + Subclass of OptionParser that also examines boot arguments. + + If the "bootarg_prefix" keyword argument is set, it's assumed that all + bootargs will start with that prefix. + + "require_prefix" is a bool: + False: accept the argument with or without the prefix. + True: ignore the argument without the prefix. (default) + """ + def __init__(self, *args, **kwargs): + self._boot_arg = dict() + self.bootarg_prefix = kwargs.pop("bootarg_prefix","") + self.require_prefix = kwargs.pop("require_prefix",True) + OptionParser.__init__(self, *args, **kwargs) + + def add_option(self, *args, **kwargs): + """ + Add a new option - like OptionParser.add_option. + + The long options will be added to the list of boot args, unless + the keyword argument 'bootarg' is set to False. + + Positional arguments that don't start with '-' are considered extra + boot args to look for. + + NOTE: conflict_handler is currently ignored for boot args - they will + always raise OptionConflictError if they conflict. + """ + # TODO: add kwargs to make an option commandline-only or boot-arg-only + flags = [a for a in args if a.startswith('-')] + bootargs = [a for a in args if not a.startswith('-')] + do_bootarg = kwargs.pop("bootarg", True) + option = OptionParser.add_option(self, *flags, **kwargs) + bootargs += [flag[2:] for flag in option._long_opts] + if do_bootarg: + for b in bootargs: + if b in self._boot_arg: + raise OptionConflictError( + "conflicting bootopt string: %s" % b, option) + else: + self._boot_arg[b] = option + return option + + def _get_bootarg_option(self, arg): + """Find the correct Option for a given bootarg (if one exists)""" + if self.bootarg_prefix and arg.startswith(self.bootarg_prefix): + prefixed_option = True + arg = arg[len(self.bootarg_prefix):] + else: + prefixed_option = False + option = self._boot_arg.get(arg) + + if self.require_prefix and not prefixed_option: + return None + if option and self.bootarg_prefix and not prefixed_option: + self.deprecated_bootargs.append(arg) + return option + + def parse_boot_cmdline(self, cmdline, values=None): + """ + Parse the boot cmdline and set appropriate values according to + the options set by add_option. + + cmdline can be given as a string (to be parsed by BootArgs), or a + dict (or any object with .iteritems()) of {bootarg:value} pairs. + + If cmdline is None, the cmdline data will be whatever BootArgs reads + by default (/proc/cmdline, /run/initramfs/etc/cmdline, /etc/cmdline). + + If an option requires a value but the boot arg doesn't provide one, + we'll quietly not set anything. + """ + if cmdline is None or type(cmdline) is str: + bootargs = BootArgs(cmdline) + else: + bootargs = cmdline + self.deprecated_bootargs = [] + for arg, val in bootargs.iteritems(): + option = self._get_bootarg_option(arg) + if option is None: + continue + if option.takes_value() and val is None: + continue # TODO: emit a warning or something there? + if option.action == "store_true" and val in ("0", "no", "off"): + # special case: "mpath=0" would otherwise set mpath to True + setattr(values, option.dest, False) + continue + option.process(arg, val, values, self) + return values + + def parse_args(self, args=None, values=None, cmdline=None): + """ + Like OptionParser.parse_args(), but also parses the boot cmdline. + (see parse_boot_cmdline for details on that process.) + Commandline arguments will override boot arguments. + """ + if values is None: + values = self.get_default_values() + v = self.parse_boot_cmdline(cmdline, values) + return OptionParser.parse_args(self, args, v) |