diff options
Diffstat (limited to 'scripts/lib/mic/3rdparty/pykickstart/base.py')
| -rw-r--r-- | scripts/lib/mic/3rdparty/pykickstart/base.py | 466 |
1 files changed, 466 insertions, 0 deletions
diff --git a/scripts/lib/mic/3rdparty/pykickstart/base.py b/scripts/lib/mic/3rdparty/pykickstart/base.py new file mode 100644 index 0000000000..e6c8f56f9d --- /dev/null +++ b/scripts/lib/mic/3rdparty/pykickstart/base.py | |||
| @@ -0,0 +1,466 @@ | |||
| 1 | # | ||
| 2 | # Chris Lumens <clumens@redhat.com> | ||
| 3 | # | ||
| 4 | # Copyright 2006, 2007, 2008 Red Hat, Inc. | ||
| 5 | # | ||
| 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. | ||
| 12 | # | ||
| 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. | ||
| 19 | # | ||
| 20 | """ | ||
| 21 | Base classes for creating commands and syntax version object. | ||
| 22 | |||
| 23 | This module exports several important base classes: | ||
| 24 | |||
| 25 | BaseData - The base abstract class for all data objects. Data objects | ||
| 26 | are contained within a BaseHandler object. | ||
| 27 | |||
| 28 | BaseHandler - The base abstract class from which versioned kickstart | ||
| 29 | handler are derived. Subclasses of BaseHandler hold | ||
| 30 | BaseData and KickstartCommand objects. | ||
| 31 | |||
| 32 | DeprecatedCommand - An abstract subclass of KickstartCommand that should | ||
| 33 | be further subclassed by users of this module. When | ||
| 34 | a subclass is used, a warning message will be | ||
| 35 | printed. | ||
| 36 | |||
| 37 | KickstartCommand - The base abstract class for all kickstart commands. | ||
| 38 | Command objects are contained within a BaseHandler | ||
| 39 | object. | ||
| 40 | """ | ||
| 41 | import gettext | ||
| 42 | gettext.textdomain("pykickstart") | ||
| 43 | _ = lambda x: gettext.ldgettext("pykickstart", x) | ||
| 44 | |||
| 45 | import types | ||
| 46 | import warnings | ||
| 47 | from pykickstart.errors import * | ||
| 48 | from pykickstart.ko import * | ||
| 49 | from pykickstart.parser import Packages | ||
| 50 | from pykickstart.version import versionToString | ||
| 51 | |||
| 52 | ### | ||
| 53 | ### COMMANDS | ||
| 54 | ### | ||
| 55 | class KickstartCommand(KickstartObject): | ||
| 56 | """The base class for all kickstart commands. This is an abstract class.""" | ||
| 57 | removedKeywords = [] | ||
| 58 | removedAttrs = [] | ||
| 59 | |||
| 60 | def __init__(self, writePriority=0, *args, **kwargs): | ||
| 61 | """Create a new KickstartCommand instance. This method must be | ||
| 62 | provided by all subclasses, but subclasses must call | ||
| 63 | KickstartCommand.__init__ first. Instance attributes: | ||
| 64 | |||
| 65 | currentCmd -- The name of the command in the input file that | ||
| 66 | caused this handler to be run. | ||
| 67 | currentLine -- The current unprocessed line from the input file | ||
| 68 | that caused this handler to be run. | ||
| 69 | handler -- A reference to the BaseHandler subclass this | ||
| 70 | command is contained withing. This is needed to | ||
| 71 | allow referencing of Data objects. | ||
| 72 | lineno -- The current line number in the input file. | ||
| 73 | writePriority -- An integer specifying when this command should be | ||
| 74 | printed when iterating over all commands' __str__ | ||
| 75 | methods. The higher the number, the later this | ||
| 76 | command will be written. All commands with the | ||
| 77 | same priority will be written alphabetically. | ||
| 78 | """ | ||
| 79 | |||
| 80 | # We don't want people using this class by itself. | ||
| 81 | if self.__class__ is KickstartCommand: | ||
| 82 | raise TypeError, "KickstartCommand is an abstract class." | ||
| 83 | |||
| 84 | KickstartObject.__init__(self, *args, **kwargs) | ||
| 85 | |||
| 86 | self.writePriority = writePriority | ||
| 87 | |||
| 88 | # These will be set by the dispatcher. | ||
| 89 | self.currentCmd = "" | ||
| 90 | self.currentLine = "" | ||
| 91 | self.handler = None | ||
| 92 | self.lineno = 0 | ||
| 93 | |||
| 94 | # If a subclass provides a removedKeywords list, remove all the | ||
| 95 | # members from the kwargs list before we start processing it. This | ||
| 96 | # ensures that subclasses don't continue to recognize arguments that | ||
| 97 | # were removed. | ||
| 98 | for arg in filter(kwargs.has_key, self.removedKeywords): | ||
| 99 | kwargs.pop(arg) | ||
| 100 | |||
| 101 | def __call__(self, *args, **kwargs): | ||
| 102 | """Set multiple attributes on a subclass of KickstartCommand at once | ||
| 103 | via keyword arguments. Valid attributes are anything specified in | ||
| 104 | a subclass, but unknown attributes will be ignored. | ||
| 105 | """ | ||
| 106 | for (key, val) in kwargs.items(): | ||
| 107 | # Ignore setting attributes that were removed in a subclass, as | ||
| 108 | # if they were unknown attributes. | ||
| 109 | if key in self.removedAttrs: | ||
| 110 | continue | ||
| 111 | |||
| 112 | if hasattr(self, key): | ||
| 113 | setattr(self, key, val) | ||
| 114 | |||
| 115 | def __str__(self): | ||
| 116 | """Return a string formatted for output to a kickstart file. This | ||
| 117 | method must be provided by all subclasses. | ||
| 118 | """ | ||
| 119 | return KickstartObject.__str__(self) | ||
| 120 | |||
| 121 | def parse(self, args): | ||
| 122 | """Parse the list of args and set data on the KickstartCommand object. | ||
| 123 | This method must be provided by all subclasses. | ||
| 124 | """ | ||
| 125 | raise TypeError, "parse() not implemented for KickstartCommand" | ||
| 126 | |||
| 127 | def apply(self, instroot="/"): | ||
| 128 | """Write out the configuration related to the KickstartCommand object. | ||
| 129 | Subclasses which do not provide this method will not have their | ||
| 130 | configuration written out. | ||
| 131 | """ | ||
| 132 | return | ||
| 133 | |||
| 134 | def dataList(self): | ||
| 135 | """For commands that can occur multiple times in a single kickstart | ||
| 136 | file (like network, part, etc.), return the list that we should | ||
| 137 | append more data objects to. | ||
| 138 | """ | ||
| 139 | return None | ||
| 140 | |||
| 141 | def deleteRemovedAttrs(self): | ||
| 142 | """Remove all attributes from self that are given in the removedAttrs | ||
| 143 | list. This method should be called from __init__ in a subclass, | ||
| 144 | but only after the superclass's __init__ method has been called. | ||
| 145 | """ | ||
| 146 | for attr in filter(lambda k: hasattr(self, k), self.removedAttrs): | ||
| 147 | delattr(self, attr) | ||
| 148 | |||
| 149 | # Set the contents of the opts object (an instance of optparse.Values | ||
| 150 | # returned by parse_args) as attributes on the KickstartCommand object. | ||
| 151 | # It's useful to call this from KickstartCommand subclasses after parsing | ||
| 152 | # the arguments. | ||
| 153 | def _setToSelf(self, optParser, opts): | ||
| 154 | self._setToObj(optParser, opts, self) | ||
| 155 | |||
| 156 | # Sets the contents of the opts object (an instance of optparse.Values | ||
| 157 | # returned by parse_args) as attributes on the provided object obj. It's | ||
| 158 | # useful to call this from KickstartCommand subclasses that handle lists | ||
| 159 | # of objects (like partitions, network devices, etc.) and need to populate | ||
| 160 | # a Data object. | ||
| 161 | def _setToObj(self, optParser, opts, obj): | ||
| 162 | for key in filter (lambda k: getattr(opts, k) != None, optParser.keys()): | ||
| 163 | setattr(obj, key, getattr(opts, key)) | ||
| 164 | |||
| 165 | class DeprecatedCommand(KickstartCommand): | ||
| 166 | """Specify that a command is deprecated and no longer has any function. | ||
| 167 | Any command that is deprecated should be subclassed from this class, | ||
| 168 | only specifying an __init__ method that calls the superclass's __init__. | ||
| 169 | This is an abstract class. | ||
| 170 | """ | ||
| 171 | def __init__(self, writePriority=None, *args, **kwargs): | ||
| 172 | # We don't want people using this class by itself. | ||
| 173 | if self.__class__ is KickstartCommand: | ||
| 174 | raise TypeError, "DeprecatedCommand is an abstract class." | ||
| 175 | |||
| 176 | # Create a new DeprecatedCommand instance. | ||
| 177 | KickstartCommand.__init__(self, writePriority, *args, **kwargs) | ||
| 178 | |||
| 179 | def __str__(self): | ||
| 180 | """Placeholder since DeprecatedCommands don't work anymore.""" | ||
| 181 | return "" | ||
| 182 | |||
| 183 | def parse(self, args): | ||
| 184 | """Print a warning message if the command is seen in the input file.""" | ||
| 185 | mapping = {"lineno": self.lineno, "cmd": self.currentCmd} | ||
| 186 | warnings.warn(_("Ignoring deprecated command on line %(lineno)s: The %(cmd)s command 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 command.") % mapping, DeprecationWarning) | ||
| 187 | |||
| 188 | |||
| 189 | ### | ||
| 190 | ### HANDLERS | ||
| 191 | ### | ||
| 192 | class BaseHandler(KickstartObject): | ||
| 193 | """Each version of kickstart syntax is provided by a subclass of this | ||
| 194 | class. These subclasses are what users will interact with for parsing, | ||
| 195 | extracting data, and writing out kickstart files. This is an abstract | ||
| 196 | class. | ||
| 197 | |||
| 198 | version -- The version this syntax handler supports. This is set by | ||
| 199 | a class attribute of a BaseHandler subclass and is used to | ||
| 200 | set up the command dict. It is for read-only use. | ||
| 201 | """ | ||
| 202 | version = None | ||
| 203 | |||
| 204 | def __init__(self, mapping=None, dataMapping=None, commandUpdates=None, | ||
| 205 | dataUpdates=None, *args, **kwargs): | ||
| 206 | """Create a new BaseHandler instance. This method must be provided by | ||
| 207 | all subclasses, but subclasses must call BaseHandler.__init__ first. | ||
| 208 | |||
| 209 | mapping -- A custom map from command strings to classes, | ||
| 210 | useful when creating your own handler with | ||
| 211 | special command objects. It is otherwise unused | ||
| 212 | and rarely needed. If you give this argument, | ||
| 213 | the mapping takes the place of the default one | ||
| 214 | and so must include all commands you want | ||
| 215 | recognized. | ||
| 216 | dataMapping -- This is the same as mapping, but for data | ||
| 217 | objects. All the same comments apply. | ||
| 218 | commandUpdates -- This is similar to mapping, but does not take | ||
| 219 | the place of the defaults entirely. Instead, | ||
| 220 | this mapping is applied after the defaults and | ||
| 221 | updates it with just the commands you want to | ||
| 222 | modify. | ||
| 223 | dataUpdates -- This is the same as commandUpdates, but for | ||
| 224 | data objects. | ||
| 225 | |||
| 226 | |||
| 227 | Instance attributes: | ||
| 228 | |||
| 229 | commands -- A mapping from a string command to a KickstartCommand | ||
| 230 | subclass object that handles it. Multiple strings can | ||
| 231 | map to the same object, but only one instance of the | ||
| 232 | command object should ever exist. Most users should | ||
| 233 | never have to deal with this directly, as it is | ||
| 234 | manipulated internally and called through dispatcher. | ||
| 235 | currentLine -- The current unprocessed line from the input file | ||
| 236 | that caused this handler to be run. | ||
| 237 | packages -- An instance of pykickstart.parser.Packages which | ||
| 238 | describes the packages section of the input file. | ||
| 239 | platform -- A string describing the hardware platform, which is | ||
| 240 | needed only by system-config-kickstart. | ||
| 241 | scripts -- A list of pykickstart.parser.Script instances, which is | ||
| 242 | populated by KickstartParser.addScript and describes the | ||
| 243 | %pre/%post/%traceback script section of the input file. | ||
| 244 | """ | ||
| 245 | |||
| 246 | # We don't want people using this class by itself. | ||
| 247 | if self.__class__ is BaseHandler: | ||
| 248 | raise TypeError, "BaseHandler is an abstract class." | ||
| 249 | |||
| 250 | KickstartObject.__init__(self, *args, **kwargs) | ||
| 251 | |||
| 252 | # This isn't really a good place for these, but it's better than | ||
| 253 | # everything else I can think of. | ||
| 254 | self.scripts = [] | ||
| 255 | self.packages = Packages() | ||
| 256 | self.platform = "" | ||
| 257 | |||
| 258 | # These will be set by the dispatcher. | ||
| 259 | self.commands = {} | ||
| 260 | self.currentLine = 0 | ||
| 261 | |||
| 262 | # A dict keyed by an integer priority number, with each value being a | ||
| 263 | # list of KickstartCommand subclasses. This dict is maintained by | ||
| 264 | # registerCommand and used in __str__. No one else should be touching | ||
| 265 | # it. | ||
| 266 | self._writeOrder = {} | ||
| 267 | |||
| 268 | self._registerCommands(mapping, dataMapping, commandUpdates, dataUpdates) | ||
| 269 | |||
| 270 | def __str__(self): | ||
| 271 | """Return a string formatted for output to a kickstart file.""" | ||
| 272 | retval = "" | ||
| 273 | |||
| 274 | if self.platform != "": | ||
| 275 | retval += "#platform=%s\n" % self.platform | ||
| 276 | |||
| 277 | retval += "#version=%s\n" % versionToString(self.version) | ||
| 278 | |||
| 279 | lst = self._writeOrder.keys() | ||
| 280 | lst.sort() | ||
| 281 | |||
| 282 | for prio in lst: | ||
| 283 | for obj in self._writeOrder[prio]: | ||
| 284 | retval += obj.__str__() | ||
| 285 | |||
| 286 | for script in self.scripts: | ||
| 287 | retval += script.__str__() | ||
| 288 | |||
| 289 | retval += self.packages.__str__() | ||
| 290 | |||
| 291 | return retval | ||
| 292 | |||
| 293 | def _insertSorted(self, lst, obj): | ||
| 294 | length = len(lst) | ||
| 295 | i = 0 | ||
| 296 | |||
| 297 | while i < length: | ||
| 298 | # If the two classes have the same name, it's because we are | ||
| 299 | # overriding an existing class with one from a later kickstart | ||
| 300 | # version, so remove the old one in favor of the new one. | ||
| 301 | if obj.__class__.__name__ > lst[i].__class__.__name__: | ||
| 302 | i += 1 | ||
| 303 | elif obj.__class__.__name__ == lst[i].__class__.__name__: | ||
| 304 | lst[i] = obj | ||
| 305 | return | ||
| 306 | elif obj.__class__.__name__ < lst[i].__class__.__name__: | ||
| 307 | break | ||
| 308 | |||
| 309 | if i >= length: | ||
| 310 | lst.append(obj) | ||
| 311 | else: | ||
| 312 | lst.insert(i, obj) | ||
| 313 | |||
| 314 | def _setCommand(self, cmdObj): | ||
| 315 | # Add an attribute on this version object. We need this to provide a | ||
| 316 | # way for clients to access the command objects. We also need to strip | ||
| 317 | # off the version part from the front of the name. | ||
| 318 | if cmdObj.__class__.__name__.find("_") != -1: | ||
| 319 | name = unicode(cmdObj.__class__.__name__.split("_", 1)[1]) | ||
| 320 | else: | ||
| 321 | name = unicode(cmdObj.__class__.__name__).lower() | ||
| 322 | |||
| 323 | setattr(self, name.lower(), cmdObj) | ||
| 324 | |||
| 325 | # Also, add the object into the _writeOrder dict in the right place. | ||
| 326 | if cmdObj.writePriority is not None: | ||
| 327 | if self._writeOrder.has_key(cmdObj.writePriority): | ||
| 328 | self._insertSorted(self._writeOrder[cmdObj.writePriority], cmdObj) | ||
| 329 | else: | ||
| 330 | self._writeOrder[cmdObj.writePriority] = [cmdObj] | ||
| 331 | |||
| 332 | def _registerCommands(self, mapping=None, dataMapping=None, commandUpdates=None, | ||
| 333 | dataUpdates=None): | ||
| 334 | if mapping == {} or mapping == None: | ||
| 335 | from pykickstart.handlers.control import commandMap | ||
| 336 | cMap = commandMap[self.version] | ||
| 337 | else: | ||
| 338 | cMap = mapping | ||
| 339 | |||
| 340 | if dataMapping == {} or dataMapping == None: | ||
| 341 | from pykickstart.handlers.control import dataMap | ||
| 342 | dMap = dataMap[self.version] | ||
| 343 | else: | ||
| 344 | dMap = dataMapping | ||
| 345 | |||
| 346 | if type(commandUpdates) == types.DictType: | ||
| 347 | cMap.update(commandUpdates) | ||
| 348 | |||
| 349 | if type(dataUpdates) == types.DictType: | ||
| 350 | dMap.update(dataUpdates) | ||
| 351 | |||
| 352 | for (cmdName, cmdClass) in cMap.iteritems(): | ||
| 353 | # First make sure we haven't instantiated this command handler | ||
| 354 | # already. If we have, we just need to make another mapping to | ||
| 355 | # it in self.commands. | ||
| 356 | cmdObj = None | ||
| 357 | |||
| 358 | for (key, val) in self.commands.iteritems(): | ||
| 359 | if val.__class__.__name__ == cmdClass.__name__: | ||
| 360 | cmdObj = val | ||
| 361 | break | ||
| 362 | |||
| 363 | # If we didn't find an instance in self.commands, create one now. | ||
| 364 | if cmdObj == None: | ||
| 365 | cmdObj = cmdClass() | ||
| 366 | self._setCommand(cmdObj) | ||
| 367 | |||
| 368 | # Finally, add the mapping to the commands dict. | ||
| 369 | self.commands[cmdName] = cmdObj | ||
| 370 | self.commands[cmdName].handler = self | ||
| 371 | |||
| 372 | # We also need to create attributes for the various data objects. | ||
| 373 | # No checks here because dMap is a bijection. At least, that's what | ||
| 374 | # the comment says. Hope no one screws that up. | ||
| 375 | for (dataName, dataClass) in dMap.iteritems(): | ||
| 376 | setattr(self, dataName, dataClass) | ||
| 377 | |||
| 378 | def dispatcher(self, args, lineno): | ||
| 379 | """Call the appropriate KickstartCommand handler for the current line | ||
| 380 | in the kickstart file. A handler for the current command should | ||
| 381 | be registered, though a handler of None is not an error. Returns | ||
| 382 | the data object returned by KickstartCommand.parse. | ||
| 383 | |||
| 384 | args -- A list of arguments to the current command | ||
| 385 | lineno -- The line number in the file, for error reporting | ||
| 386 | """ | ||
| 387 | cmd = args[0] | ||
| 388 | |||
| 389 | if not self.commands.has_key(cmd): | ||
| 390 | raise KickstartParseError, formatErrorMsg(lineno, msg=_("Unknown command: %s" % cmd)) | ||
| 391 | elif self.commands[cmd] != None: | ||
| 392 | self.commands[cmd].currentCmd = cmd | ||
| 393 | self.commands[cmd].currentLine = self.currentLine | ||
| 394 | self.commands[cmd].lineno = lineno | ||
| 395 | |||
| 396 | # The parser returns the data object that was modified. This could | ||
| 397 | # be a BaseData subclass that should be put into a list, or it | ||
| 398 | # could be the command handler object itself. | ||
| 399 | obj = self.commands[cmd].parse(args[1:]) | ||
| 400 | lst = self.commands[cmd].dataList() | ||
| 401 | if lst is not None: | ||
| 402 | lst.append(obj) | ||
| 403 | |||
| 404 | return obj | ||
| 405 | |||
| 406 | def maskAllExcept(self, lst): | ||
| 407 | """Set all entries in the commands dict to None, except the ones in | ||
| 408 | the lst. All other commands will not be processed. | ||
| 409 | """ | ||
| 410 | self._writeOrder = {} | ||
| 411 | |||
| 412 | for (key, val) in self.commands.iteritems(): | ||
| 413 | if not key in lst: | ||
| 414 | self.commands[key] = None | ||
| 415 | |||
| 416 | def hasCommand(self, cmd): | ||
| 417 | """Return true if there is a handler for the string cmd.""" | ||
| 418 | return hasattr(self, cmd) | ||
| 419 | |||
| 420 | |||
| 421 | ### | ||
| 422 | ### DATA | ||
| 423 | ### | ||
| 424 | class BaseData(KickstartObject): | ||
| 425 | """The base class for all data objects. This is an abstract class.""" | ||
| 426 | removedKeywords = [] | ||
| 427 | removedAttrs = [] | ||
| 428 | |||
| 429 | def __init__(self, *args, **kwargs): | ||
| 430 | """Create a new BaseData instance. | ||
| 431 | |||
| 432 | lineno -- Line number in the ks-file where this object was defined | ||
| 433 | """ | ||
| 434 | |||
| 435 | # We don't want people using this class by itself. | ||
| 436 | if self.__class__ is BaseData: | ||
| 437 | raise TypeError, "BaseData is an abstract class." | ||
| 438 | |||
| 439 | KickstartObject.__init__(self, *args, **kwargs) | ||
| 440 | self.lineno = 0 | ||
| 441 | |||
| 442 | def __str__(self): | ||
| 443 | """Return a string formatted for output to a kickstart file.""" | ||
| 444 | return "" | ||
| 445 | |||
| 446 | def __call__(self, *args, **kwargs): | ||
| 447 | """Set multiple attributes on a subclass of BaseData at once via | ||
| 448 | keyword arguments. Valid attributes are anything specified in a | ||
| 449 | subclass, but unknown attributes will be ignored. | ||
| 450 | """ | ||
| 451 | for (key, val) in kwargs.items(): | ||
| 452 | # Ignore setting attributes that were removed in a subclass, as | ||
| 453 | # if they were unknown attributes. | ||
| 454 | if key in self.removedAttrs: | ||
| 455 | continue | ||
| 456 | |||
| 457 | if hasattr(self, key): | ||
| 458 | setattr(self, key, val) | ||
| 459 | |||
| 460 | def deleteRemovedAttrs(self): | ||
| 461 | """Remove all attributes from self that are given in the removedAttrs | ||
| 462 | list. This method should be called from __init__ in a subclass, | ||
| 463 | but only after the superclass's __init__ method has been called. | ||
| 464 | """ | ||
| 465 | for attr in filter(lambda k: hasattr(self, k), self.removedAttrs): | ||
| 466 | delattr(self, attr) | ||
