205 lines
8.7 KiB
Python
205 lines
8.7 KiB
Python
#
|
|
# Chris Lumens <clumens@redhat.com>
|
|
#
|
|
# Copyright 2005, 2006, 2007 Red Hat, Inc.
|
|
#
|
|
# This copyrighted material is made available to anyone wishing to use, modify,
|
|
# copy, or redistribute it subject to the terms and conditions of the GNU
|
|
# General Public License v.2. This program is distributed in the hope that it
|
|
# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
|
|
# implied warranties 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, write to the Free Software Foundation, Inc., 51
|
|
# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
|
|
# trademarks that are incorporated in the source code or documentation are not
|
|
# subject to the GNU General Public License and may only be used or replicated
|
|
# with the express permission of Red Hat, Inc.
|
|
#
|
|
"""
|
|
Specialized option handling.
|
|
|
|
This module exports two classes:
|
|
|
|
KSOptionParser - A specialized subclass of OptionParser to be used
|
|
in BaseHandler subclasses.
|
|
|
|
KSOption - A specialized subclass of Option.
|
|
"""
|
|
import warnings
|
|
from copy import copy
|
|
from optparse import *
|
|
|
|
from constants import *
|
|
from errors import *
|
|
from version import *
|
|
|
|
import gettext
|
|
_ = lambda x: gettext.ldgettext("pykickstart", x)
|
|
|
|
class KSOptionParser(OptionParser):
|
|
"""A specialized subclass of optparse.OptionParser to handle extra option
|
|
attribute checking, work error reporting into the KickstartParseError
|
|
framework, and to turn off the default help.
|
|
"""
|
|
def exit(self, status=0, msg=None):
|
|
pass
|
|
|
|
def error(self, msg):
|
|
if self.lineno != None:
|
|
raise KickstartParseError, formatErrorMsg(self.lineno, msg=msg)
|
|
else:
|
|
raise KickstartParseError, msg
|
|
|
|
def keys(self):
|
|
retval = []
|
|
|
|
for opt in self.option_list:
|
|
if opt not in retval:
|
|
retval.append(opt.dest)
|
|
|
|
return retval
|
|
|
|
def _init_parsing_state (self):
|
|
OptionParser._init_parsing_state(self)
|
|
self.option_seen = {}
|
|
|
|
def check_values (self, values, args):
|
|
def seen(self, option):
|
|
return self.option_seen.has_key(option)
|
|
|
|
def usedTooNew(self, option):
|
|
return option.introduced and option.introduced > self.version
|
|
|
|
def usedDeprecated(self, option):
|
|
return option.deprecated
|
|
|
|
def usedRemoved(self, option):
|
|
return option.removed and option.removed <= self.version
|
|
|
|
for option in filter(lambda o: isinstance(o, Option), self.option_list):
|
|
if option.required and not seen(self, option):
|
|
raise KickstartValueError, formatErrorMsg(self.lineno, _("Option %s is required") % option)
|
|
elif seen(self, option) and usedTooNew(self, option):
|
|
mapping = {"option": option, "intro": versionToString(option.introduced),
|
|
"version": versionToString(self.version)}
|
|
self.error(_("The %(option)s option was introduced in version %(intro)s, but you are using kickstart syntax version %(version)s.") % mapping)
|
|
elif seen(self, option) and usedRemoved(self, option):
|
|
mapping = {"option": option, "removed": versionToString(option.removed),
|
|
"version": versionToString(self.version)}
|
|
|
|
if option.removed == self.version:
|
|
self.error(_("The %(option)s option is no longer supported.") % mapping)
|
|
else:
|
|
self.error(_("The %(option)s option was removed in version %(removed)s, but you are using kickstart syntax version %(version)s.") % mapping)
|
|
elif seen(self, option) and usedDeprecated(self, option):
|
|
mapping = {"lineno": self.lineno, "option": option}
|
|
warnings.warn(_("Ignoring deprecated option on line %(lineno)s: The %(option)s option has been deprecated and no longer has any effect. It may be removed from future releases, which will result in a fatal error from kickstart. Please modify your kickstart file to remove this option.") % mapping, DeprecationWarning)
|
|
|
|
return (values, args)
|
|
|
|
def parse_args(self, *args, **kwargs):
|
|
if kwargs.has_key("lineno"):
|
|
self.lineno = kwargs.pop("lineno")
|
|
|
|
return OptionParser.parse_args(self, **kwargs)
|
|
|
|
def __init__(self, mapping=None, version=None):
|
|
"""Create a new KSOptionParser instance. Each KickstartCommand
|
|
subclass should create one instance of KSOptionParser, providing
|
|
at least the lineno attribute. mapping and version are not required.
|
|
Instance attributes:
|
|
|
|
mapping -- A mapping from option strings to different values.
|
|
version -- The version of the kickstart syntax we are checking
|
|
against.
|
|
"""
|
|
OptionParser.__init__(self, option_class=KSOption,
|
|
add_help_option=False,
|
|
conflict_handler="resolve")
|
|
if mapping is None:
|
|
self.map = {}
|
|
else:
|
|
self.map = mapping
|
|
|
|
self.lineno = None
|
|
self.option_seen = {}
|
|
self.version = version
|
|
|
|
def _check_ksboolean(option, opt, value):
|
|
if value.lower() in ("on", "yes", "true", "1"):
|
|
return True
|
|
elif value.lower() in ("off", "no", "false", "0"):
|
|
return False
|
|
else:
|
|
mapping = {"opt": opt, "value": value}
|
|
raise OptionValueError(_("Option %(opt)s: invalid boolean value: %(value)r") % mapping)
|
|
|
|
def _check_string(option, opt, value):
|
|
if len(value) > 2 and value.startswith("--"):
|
|
mapping = {"opt": opt, "value": value}
|
|
raise OptionValueError(_("Option %(opt)s: invalid string value: %(value)r") % mapping)
|
|
else:
|
|
return value
|
|
|
|
# Creates a new Option class that supports several new attributes:
|
|
# - required: any option with this attribute must be supplied or an exception
|
|
# is thrown
|
|
# - introduced: the kickstart syntax version that this option first appeared
|
|
# in - an exception will be raised if the option is used and
|
|
# the specified syntax version is less than the value of this
|
|
# attribute
|
|
# - deprecated: the kickstart syntax version that this option was deprecated
|
|
# in - a DeprecationWarning will be thrown if the option is
|
|
# used and the specified syntax version is greater than the
|
|
# value of this attribute
|
|
# - removed: the kickstart syntax version that this option was removed in - an
|
|
# exception will be raised if the option is used and the specified
|
|
# syntax version is greated than the value of this attribute
|
|
# Also creates a new type:
|
|
# - ksboolean: support various kinds of boolean values on an option
|
|
# And two new actions:
|
|
# - map : allows you to define an opt -> val mapping such that dest gets val
|
|
# when opt is seen
|
|
# - map_extend: allows you to define an opt -> [val1, ... valn] mapping such
|
|
# that dest gets a list of vals built up when opt is seen
|
|
class KSOption (Option):
|
|
ATTRS = Option.ATTRS + ['introduced', 'deprecated', 'removed', 'required']
|
|
ACTIONS = Option.ACTIONS + ("map", "map_extend",)
|
|
STORE_ACTIONS = Option.STORE_ACTIONS + ("map", "map_extend",)
|
|
|
|
TYPES = Option.TYPES + ("ksboolean", "string")
|
|
TYPE_CHECKER = copy(Option.TYPE_CHECKER)
|
|
TYPE_CHECKER["ksboolean"] = _check_ksboolean
|
|
TYPE_CHECKER["string"] = _check_string
|
|
|
|
def _check_required(self):
|
|
if self.required and not self.takes_value():
|
|
raise OptionError(_("Required flag set for option that doesn't take a value"), self)
|
|
|
|
# Make sure _check_required() is called from the constructor!
|
|
CHECK_METHODS = Option.CHECK_METHODS + [_check_required]
|
|
|
|
def process (self, opt, value, values, parser):
|
|
Option.process(self, opt, value, values, parser)
|
|
parser.option_seen[self] = 1
|
|
|
|
# Override default take_action method to handle our custom actions.
|
|
def take_action(self, action, dest, opt, value, values, parser):
|
|
if action == "map":
|
|
values.ensure_value(dest, parser.map[opt.lstrip('-')])
|
|
elif action == "map_extend":
|
|
values.ensure_value(dest, []).extend(parser.map[opt.lstrip('-')])
|
|
else:
|
|
Option.take_action(self, action, dest, opt, value, values, parser)
|
|
|
|
def takes_value(self):
|
|
# Deprecated options don't take a value.
|
|
return Option.takes_value(self) and not self.deprecated
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
self.deprecated = False
|
|
self.required = False
|
|
Option.__init__(self, *args, **kwargs)
|