Add new RHEL7 logvol objects to master
[pykickstart.git] / pykickstart / options.py
blob08320827f7a8dd26a730818072bfcad1134bfb00
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.
20 """
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.
29 """
30 import warnings
31 from copy import copy
32 from optparse import Option, OptionError, OptionParser, OptionValueError
34 from pykickstart.errors import KickstartParseError, KickstartValueError, formatErrorMsg
35 from pykickstart.version import versionToString
37 import gettext
38 _ = lambda x: gettext.ldgettext("pykickstart", x)
40 class KSOptionParser(OptionParser):
41 """A specialized subclass of optparse.OptionParser to handle extra option
42 attribute checking, work error reporting into the KickstartParseError
43 framework, and to turn off the default help.
44 """
45 def exit(self, status=0, msg=None):
46 pass
48 def error(self, msg):
49 if self.lineno != None:
50 raise KickstartParseError(formatErrorMsg(self.lineno, msg=msg))
51 else:
52 raise KickstartParseError(msg)
54 def keys(self):
55 retval = []
57 for opt in self.option_list:
58 if opt not in retval:
59 retval.append(opt.dest)
61 return retval
63 def _init_parsing_state (self):
64 OptionParser._init_parsing_state(self)
65 self.option_seen = {}
67 def check_values (self, values, args):
68 def seen(option):
69 return option in self.option_seen
71 def usedTooNew(option):
72 return option.introduced and option.introduced > self.version
74 def usedDeprecated(option):
75 return option.deprecated
77 def usedRemoved(option):
78 return option.removed and option.removed <= self.version
80 for option in [o for o in self.option_list if isinstance(o, Option)]:
81 if option.required and not seen(option):
82 raise KickstartValueError(formatErrorMsg(self.lineno, _("Option %s is required") % option))
83 elif seen(option) and usedTooNew(option):
84 mapping = {"option": option, "intro": versionToString(option.introduced),
85 "version": versionToString(self.version)}
86 self.error(_("The %(option)s option was introduced in version %(intro)s, but you are using kickstart syntax version %(version)s.") % mapping)
87 elif seen(option) and usedRemoved(option):
88 mapping = {"option": option, "removed": versionToString(option.removed),
89 "version": versionToString(self.version)}
91 if option.removed == self.version:
92 self.error(_("The %(option)s option is no longer supported.") % mapping)
93 else:
94 self.error(_("The %(option)s option was removed in version %(removed)s, but you are using kickstart syntax version %(version)s.") % mapping)
95 elif seen(option) and usedDeprecated(option) and self.version >= option.deprecated:
96 mapping = {"lineno": self.lineno, "option": option}
97 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)
99 return (values, args)
101 def parse_args(self, *args, **kwargs):
102 if "lineno" in kwargs:
103 self.lineno = kwargs.pop("lineno")
105 return OptionParser.parse_args(self, **kwargs)
107 def __init__(self, mapping=None, version=None):
108 """Create a new KSOptionParser instance. Each KickstartCommand
109 subclass should create one instance of KSOptionParser, providing
110 at least the lineno attribute. mapping and version are not required.
111 Instance attributes:
113 mapping -- A mapping from option strings to different values.
114 version -- The version of the kickstart syntax we are checking
115 against.
117 OptionParser.__init__(self, option_class=KSOption,
118 add_help_option=False,
119 conflict_handler="resolve")
120 if mapping is None:
121 self.map = {}
122 else:
123 self.map = mapping
125 self.lineno = None
126 self.option_seen = {}
127 self.version = version
129 def _check_ksboolean(_option, opt, value):
130 if value.lower() in ("on", "yes", "true", "1"):
131 return True
132 elif value.lower() in ("off", "no", "false", "0"):
133 return False
134 else:
135 mapping = {"opt": opt, "value": value}
136 raise OptionValueError(_("Option %(opt)s: invalid boolean value: %(value)r") % mapping)
138 def _check_string(_option, opt, value):
139 if len(value) > 2 and value.startswith("--"):
140 mapping = {"opt": opt, "value": value}
141 raise OptionValueError(_("Option %(opt)s: invalid string value: %(value)r") % mapping)
142 else:
143 return value
145 # Creates a new Option class that supports several new attributes:
146 # - required: any option with this attribute must be supplied or an exception
147 # is thrown
148 # - introduced: the kickstart syntax version that this option first appeared
149 # in - an exception will be raised if the option is used and
150 # the specified syntax version is less than the value of this
151 # attribute
152 # - deprecated: the kickstart syntax version that this option was deprecated
153 # in - a DeprecationWarning will be thrown if the option is
154 # used and the specified syntax version is greater than the
155 # value of this attribute
156 # - removed: the kickstart syntax version that this option was removed in - an
157 # exception will be raised if the option is used and the specified
158 # syntax version is greated than the value of this attribute
159 # Also creates a new type:
160 # - ksboolean: support various kinds of boolean values on an option
161 # And two new actions:
162 # - map : allows you to define an opt -> val mapping such that dest gets val
163 # when opt is seen
164 # - map_extend: allows you to define an opt -> [val1, ... valn] mapping such
165 # that dest gets a list of vals built up when opt is seen
166 class KSOption (Option):
167 ATTRS = Option.ATTRS + ['introduced', 'deprecated', 'removed', 'required']
168 ACTIONS = Option.ACTIONS + ("map", "map_extend",)
169 STORE_ACTIONS = Option.STORE_ACTIONS + ("map", "map_extend",)
171 TYPES = Option.TYPES + ("ksboolean", "string")
172 TYPE_CHECKER = copy(Option.TYPE_CHECKER)
173 TYPE_CHECKER["ksboolean"] = _check_ksboolean
174 TYPE_CHECKER["string"] = _check_string
176 def _check_required(self):
177 if self.required and not self.takes_value():
178 raise OptionError(_("Required flag set for option that doesn't take a value"), self)
180 # Make sure _check_required() is called from the constructor!
181 CHECK_METHODS = Option.CHECK_METHODS + [_check_required]
183 def process (self, opt, value, values, parser):
184 Option.process(self, opt, value, values, parser)
185 parser.option_seen[self] = 1
187 # Override default take_action method to handle our custom actions.
188 def take_action(self, action, dest, opt, value, values, parser):
189 if action == "map":
190 values.ensure_value(dest, parser.map[opt.lstrip('-')])
191 elif action == "map_extend":
192 values.ensure_value(dest, []).extend(parser.map[opt.lstrip('-')])
193 else:
194 Option.take_action(self, action, dest, opt, value, values, parser)
196 def takes_value(self):
197 # Deprecated options don't take a value.
198 return Option.takes_value(self) and not self.deprecated
200 def __init__(self, *args, **kwargs):
201 self.deprecated = False
202 self.required = False
203 Option.__init__(self, *args, **kwargs)