2 # Chris Lumens <clumens@redhat.com>
4 # Copyright 2005, 2006, 2007 Red Hat, Inc.
6 # This copyrighted material is made available to anyone wishing to use, modify,
7 # copy, or redistribute it subject to the terms and conditions of the GNU
8 # General Public License v.2. This program is distributed in the hope that it
9 # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
10 # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 # See the GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License along with
14 # this program; if not, write to the Free Software Foundation, Inc., 51
15 # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
16 # trademarks that are incorporated in the source code or documentation are not
17 # subject to the GNU General Public License and may only be used or replicated
18 # with the express permission of Red Hat, Inc.
21 Specialized option handling.
23 This module exports two classes:
25 KSOptionParser - A specialized subclass of OptionParser to be used
26 in BaseHandler subclasses.
28 KSOption - A specialized subclass of Option.
32 from optparse import *
34 from constants import *
39 _ = lambda x: gettext.ldgettext("pykickstart", x)
41 class KSOptionParser(OptionParser):
42 """A specialized subclass of optparse.OptionParser to handle extra option
43 attribute checking, work error reporting into the KickstartParseError
44 framework, and to turn off the default help.
46 def exit(self, status=0, msg=None):
50 if self.lineno != None:
51 raise KickstartParseError ( formatErrorMsg(self.lineno, msg=msg))
53 raise KickstartParseError ( msg)
58 for opt in self.option_list:
60 retval.append(opt.dest)
64 def _init_parsing_state (self):
65 OptionParser._init_parsing_state(self)
68 def check_values (self, values, args):
69 def seen(self, option):
70 return self.option_seen.has_key(option)
72 def usedTooNew(self, option):
73 return option.introduced and option.introduced > self.version
75 def usedDeprecated(self, option):
76 return option.deprecated
78 def usedRemoved(self, option):
79 return option.removed and option.removed <= self.version
81 for option in filter(lambda o: isinstance(o, Option), self.option_list):
82 if option.required and not seen(self, option):
83 raise KickstartValueError (formatErrorMsg(self.lineno, _("Option %s is required") % option))
84 elif seen(self, option) and usedTooNew(self, option):
85 mapping = {"option": option, "intro": versionToString(option.introduced),
86 "version": versionToString(self.version)}
87 self.error(_("The %(option)s option was introduced in version %(intro)s, but you are using kickstart syntax version %(version)s.") % mapping)
88 elif seen(self, option) and usedRemoved(self, option):
89 mapping = {"option": option, "removed": versionToString(option.removed),
90 "version": versionToString(self.version)}
92 if option.removed == self.version:
93 self.error(_("The %(option)s option is no longer supported.") % mapping)
95 self.error(_("The %(option)s option was removed in version %(removed)s, but you are using kickstart syntax version %(version)s.") % mapping)
96 elif seen(self, option) and usedDeprecated(self, option):
97 mapping = {"lineno": self.lineno, "option": option}
98 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)
100 return (values, args)
102 def parse_args(self, *args, **kwargs):
103 if kwargs.has_key("lineno"):
104 self.lineno = kwargs.pop("lineno")
106 return OptionParser.parse_args(self, **kwargs)
108 def __init__(self, mapping=None, version=None):
109 """Create a new KSOptionParser instance. Each KickstartCommand
110 subclass should create one instance of KSOptionParser, providing
111 at least the lineno attribute. mapping and version are not required.
114 mapping -- A mapping from option strings to different values.
115 version -- The version of the kickstart syntax we are checking
118 OptionParser.__init__(self, option_class=KSOption,
119 add_help_option=False,
120 conflict_handler="resolve")
127 self.option_seen = {}
128 self.version = version
130 def _check_ksboolean(option, opt, value):
131 if value.lower() in ("on", "yes", "true", "1"):
133 elif value.lower() in ("off", "no", "false", "0"):
136 mapping = {"opt": opt, "value": value}
137 raise OptionValueError(_("Option %(opt)s: invalid boolean value: %(value)r") % mapping)
139 def _check_string(option, opt, value):
140 #if len(value) > 2 and value.startswith("--"):
141 #mapping = {"opt": opt, "value": value}
142 #raise OptionValueError(_("Option %(opt)s: invalid string value: %(value)r") % mapping)
146 # Creates a new Option class that supports several new attributes:
147 # - required: any option with this attribute must be supplied or an exception
149 # - introduced: the kickstart syntax version that this option first appeared
150 # in - an exception will be raised if the option is used and
151 # the specified syntax version is less than the value of this
153 # - deprecated: the kickstart syntax version that this option was deprecated
154 # in - a DeprecationWarning will be thrown if the option is
155 # used and the specified syntax version is greater than the
156 # value of this attribute
157 # - removed: the kickstart syntax version that this option was removed in - an
158 # exception will be raised if the option is used and the specified
159 # syntax version is greated than the value of this attribute
160 # Also creates a new type:
161 # - ksboolean: support various kinds of boolean values on an option
162 # And two new actions:
163 # - map : allows you to define an opt -> val mapping such that dest gets val
165 # - map_extend: allows you to define an opt -> [val1, ... valn] mapping such
166 # that dest gets a list of vals built up when opt is seen
167 class KSOption (Option):
168 ATTRS = Option.ATTRS + ['introduced', 'deprecated', 'removed', 'required']
169 ACTIONS = Option.ACTIONS + ("map", "map_extend",)
170 STORE_ACTIONS = Option.STORE_ACTIONS + ("map", "map_extend",)
172 TYPES = Option.TYPES + ("ksboolean", "string")
173 TYPE_CHECKER = copy(Option.TYPE_CHECKER)
174 TYPE_CHECKER["ksboolean"] = _check_ksboolean
175 TYPE_CHECKER["string"] = _check_string
177 def _check_required(self):
178 if self.required and not self.takes_value():
179 raise OptionError(_("Required flag set for option that doesn't take a value"), self)
181 # Make sure _check_required() is called from the constructor!
182 CHECK_METHODS = Option.CHECK_METHODS + [_check_required]
184 def process (self, opt, value, values, parser):
185 Option.process(self, opt, value, values, parser)
186 parser.option_seen[self] = 1
188 # Override default take_action method to handle our custom actions.
189 def take_action(self, action, dest, opt, value, values, parser):
191 values.ensure_value(dest, parser.map[opt.lstrip('-')])
192 elif action == "map_extend":
193 values.ensure_value(dest, []).extend(parser.map[opt.lstrip('-')])
195 Option.take_action(self, action, dest, opt, value, values, parser)
197 def takes_value(self):
198 # Deprecated options don't take a value.
199 return Option.takes_value(self) and not self.deprecated
201 def __init__(self, *args, **kwargs):
202 self.deprecated = False
203 self.required = False
204 Option.__init__(self, *args, **kwargs)