Have objects in one version subclass objects in a previous version. Not
[pykickstart.git] / pykickstart / options.py
blobb7eaacdc0124887eb37d1ab1047392d484941b82
2 # Chris Lumens <clumens@redhat.com>
4 # Copyright 2005, 2006 Red Hat, Inc.
6 # This software may be freely redistributed under the terms of the GNU
7 # general public license.
9 # You should have received a copy of the GNU General Public License
10 # along with this program; if not, write to the Free Software
11 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
13 """
14 Specialized option handling.
16 This module exports two classes:
18 KSOptionParser - A specialized subclass of OptionParser to be used
19 in BaseVersion subclasses.
21 KSOption - A specialized subclass of Option.
22 """
23 import warnings
24 from copy import copy
25 from optparse import *
27 from constants import *
28 from errors import *
30 from rhpl.translate import _
31 import rhpl.translate as translate
33 translate.textdomain("pykickstart")
35 class KSOptionParser(OptionParser):
36 """A specialized subclass of optparse.OptionParser to handle extra option
37 attribute checking, work error reporting into the KickstartParseError
38 framework, and to turn off the default help.
39 """
40 def exit(self, status=0, msg=None):
41 pass
43 def error(self, msg):
44 if self.lineno != None:
45 raise KickstartParseError, formatErrorMsg(self.lineno, msg=msg)
46 else:
47 raise KickstartParseError, msg
49 def keys(self):
50 retval = []
52 for opt in self.option_list:
53 if opt not in retval:
54 retval.append(opt.dest)
56 return retval
58 def _init_parsing_state (self):
59 OptionParser._init_parsing_state(self)
60 self.option_seen = {}
62 def check_values (self, values, args):
63 def seen(self, option):
64 return self.option_seen.has_key(option)
66 def usedTooNew(self, option):
67 return option.introduced and option.introduced > self.version
69 def usedDeprecated(self, option):
70 return option.deprecated and option.deprecated <= self.version
72 def usedRemoved(self, option):
73 return option.removed and option.removed <= self.version
75 for option in filter(lambda o: isinstance(o, Option), self.option_list):
76 if option.required and not seen(self, option):
77 raise KickstartValueError, formatErrorMsg(self.lineno, _("Option %s is required") % option)
78 elif seen(self, option) and usedTooNew(self, option):
79 mapping = {"option": option, "intro": option.introduced, "version": self.version}
80 self.error(_("The option %(option)s was introduced in version %(intro)s, but you are using kickstart syntax version %(version)s") % mapping)
81 elif seen(self, option) and usedDeprecated(self, option):
82 mapping = {"lineno": self.lineno, "option": option}
83 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)
84 elif seen(self, option) and usedRemoved(self, option):
85 mapping = {"option": option, "removed": option.removed, "version": self.version}
86 self.error(_("The option %(option)s was removed in version %(removed)s, but you are using kickstart syntax version %(version)s") % mapping)
88 return (values, args)
90 def __init__(self, map={}, lineno=None, version=None):
91 """Create a new KSOptionParser instance. Each KickstartCommand
92 subclass should create one instance of KSOptionParser, providing
93 at least the lineno attribute. map and version are not required.
94 Instance attributes:
96 map -- A mapping from option strings to different values.
97 lineno -- The line number of the line this KSOptionParser instance
98 is processing.
99 version -- The version of the kickstart syntax we are checking
100 against.
102 self.map = map
103 self.lineno = lineno
104 self.version = version
105 OptionParser.__init__(self, option_class=KSOption,
106 add_help_option=False)
108 # Creates a new Option class that supports several new attributes:
109 # - required: any option with this attribute must be supplied or an exception
110 # is thrown
111 # - introduced: the kickstart syntax version that this option first appeared
112 # in - an exception will be raised if the option is used and
113 # the specified syntax version is less than the value of this
114 # attribute
115 # - deprecated: the kickstart syntax version that this option was deprecated
116 # in - a DeprecationWarning will be thrown if the option is
117 # used and the specified syntax version is greater than the
118 # value of this attribute
119 # - removed: the kickstart syntax version that this option was removed in - an
120 # exception will be raised if the option is used and the specified
121 # syntax version is greated than the value of this attribute
122 # Also creates a new type:
123 # - ksboolean: support various kinds of boolean values on an option
124 # And two new actions:
125 # - map : allows you to define an opt -> val mapping such that dest gets val
126 # when opt is seen
127 # - map_extend: allows you to define an opt -> [val1, ... valn] mapping such
128 # that dest gets a list of vals built up when opt is seen
129 class KSOption (Option):
130 ATTRS = Option.ATTRS + ['introduced', 'deprecated', 'removed', 'required']
131 ACTIONS = Option.ACTIONS + ("map", "map_extend",)
132 STORE_ACTIONS = Option.STORE_ACTIONS + ("map", "map_extend",)
134 TYPES = Option.TYPES + ("ksboolean",)
135 TYPE_CHECKER = copy(Option.TYPE_CHECKER)
137 def _check_required(self):
138 if self.required and not self.takes_value():
139 raise OptionError(_("Required flag set for option that doesn't take a value"), self)
141 def _check_ksboolean(option, opt, value):
142 if value.lower() in ("on", "yes", "true", "1"):
143 return True
144 elif value.lower() in ("off", "no", "false", "0"):
145 return False
146 else:
147 mapping = {"opt": opt, "value": value}
148 raise OptionValueError(_("Option %(opt)s: invalid boolean value: %(value)r") % mapping)
150 # Make sure _check_required() is called from the constructor!
151 CHECK_METHODS = Option.CHECK_METHODS + [_check_required]
152 TYPE_CHECKER["ksboolean"] = _check_ksboolean
154 def process (self, opt, value, values, parser):
155 Option.process(self, opt, value, values, parser)
156 parser.option_seen[self] = 1
158 # Override default take_action method to handle our custom actions.
159 def take_action(self, action, dest, opt, value, values, parser):
160 if action == "map":
161 values.ensure_value(dest, parser.map[opt.lstrip('-')])
162 elif action == "map_extend":
163 values.ensure_value(dest, []).extend(parser.map[opt.lstrip('-')])
164 else:
165 Option.take_action(self, action, dest, opt, value, values, parser)