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 Option
, OptionError
, OptionParser
, OptionValueError
34 from pykickstart
.errors
import KickstartParseError
, KickstartValueError
, formatErrorMsg
35 from pykickstart
.version
import versionToString
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.
45 def exit(self
, status
=0, msg
=None):
49 if self
.lineno
!= None:
50 raise KickstartParseError(formatErrorMsg(self
.lineno
, msg
=msg
))
52 raise KickstartParseError(msg
)
57 for opt
in self
.option_list
:
59 retval
.append(opt
.dest
)
63 def _init_parsing_state (self
):
64 OptionParser
._init
_parsing
_state
(self
)
67 def check_values (self
, values
, args
):
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
)
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)
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.
113 mapping -- A mapping from option strings to different values.
114 version -- The version of the kickstart syntax we are checking
117 OptionParser
.__init
__(self
, option_class
=KSOption
,
118 add_help_option
=False,
119 conflict_handler
="resolve")
126 self
.option_seen
= {}
127 self
.version
= version
129 def _check_ksboolean(_option
, opt
, value
):
130 if value
.lower() in ("on", "yes", "true", "1"):
132 elif value
.lower() in ("off", "no", "false", "0"):
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
)
145 # Creates a new Option class that supports several new attributes:
146 # - required: any option with this attribute must be supplied or an exception
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
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
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
):
190 values
.ensure_value(dest
, parser
.map[opt
.lstrip('-')])
191 elif action
== "map_extend":
192 values
.ensure_value(dest
, []).extend(parser
.map[opt
.lstrip('-')])
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
)