Package CedarBackup2 :: Module config
[hide private]
[frames] | no frames]

Source Code for Module CedarBackup2.config

   1  # -*- coding: iso-8859-1 -*- 
   2  # vim: set ft=python ts=3 sw=3 expandtab: 
   3  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
   4  # 
   5  #              C E D A R 
   6  #          S O L U T I O N S       "Software done right." 
   7  #           S O F T W A R E 
   8  # 
   9  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
  10  # 
  11  # Copyright (c) 2004-2007 Kenneth J. Pronovici. 
  12  # All rights reserved. 
  13  # 
  14  # This program is free software; you can redistribute it and/or 
  15  # modify it under the terms of the GNU General Public License, 
  16  # Version 2, as published by the Free Software Foundation. 
  17  # 
  18  # This program is distributed in the hope that it will be useful, 
  19  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  20  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
  21  # 
  22  # Copies of the GNU General Public License are available from 
  23  # the Free Software Foundation website, http://www.gnu.org/. 
  24  # 
  25  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
  26  # 
  27  # Author   : Kenneth J. Pronovici <pronovic@ieee.org> 
  28  # Language : Python (>= 2.3) 
  29  # Project  : Cedar Backup, release 2 
  30  # Revision : $Id: config.py 1210 2007-07-05 03:04:54Z pronovic $ 
  31  # Purpose  : Provides configuration-related objects. 
  32  # 
  33  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
  34   
  35  ######################################################################## 
  36  # Module documentation 
  37  ######################################################################## 
  38   
  39  """ 
  40  Provides configuration-related objects. 
  41   
  42  Summary 
  43  ======= 
  44   
  45     Cedar Backup stores all of its configuration in an XML document typically 
  46     called C{cback.conf}.  The standard location for this document is in 
  47     C{/etc}, but users can specify a different location if they want to.   
  48   
  49     The C{Config} class is a Python object representation of a Cedar Backup XML 
  50     configuration file.  The representation is two-way: XML data can be used to 
  51     create a C{Config} object, and then changes to the object can be propogated 
  52     back to disk.  A C{Config} object can even be used to create a configuration 
  53     file from scratch programmatically. 
  54   
  55     The C{Config} class is intended to be the only Python-language interface to 
  56     Cedar Backup configuration on disk.  Cedar Backup will use the class as its 
  57     internal representation of configuration, and applications external to Cedar 
  58     Backup itself (such as a hypothetical third-party configuration tool written 
  59     in Python or a third party extension module) should also use the class when 
  60     they need to read and write configuration files. 
  61   
  62  Backwards Compatibility 
  63  ======================= 
  64   
  65     The configuration file format has changed between Cedar Backup 1.x and Cedar 
  66     Backup 2.x.  Any Cedar Backup 1.x configuration file is also a valid Cedar 
  67     Backup 2.x configuration file.  However, it doesn't work to go the other 
  68     direction, as the 2.x configuration files may contain additional fields that 
  69     are not accepted by older versions of the software.   
  70   
  71  XML Configuration Structure 
  72  =========================== 
  73   
  74     A C{Config} object can either be created "empty", or can be created based on 
  75     XML input (either in the form of a string or read in from a file on disk). 
  76     Generally speaking, the XML input I{must} result in a C{Config} object which 
  77     passes the validations laid out below in the I{Validation} section.   
  78   
  79     An XML configuration file is composed of seven sections: 
  80   
  81        - I{reference}: specifies reference information about the file (author, revision, etc) 
  82        - I{extensions}: specifies mappings to Cedar Backup extensions (external code) 
  83        - I{options}: specifies global configuration options 
  84        - I{collect}: specifies configuration related to the collect action 
  85        - I{stage}: specifies configuration related to the stage action 
  86        - I{store}: specifies configuration related to the store action 
  87        - I{purge}: specifies configuration related to the purge action 
  88   
  89     Each section is represented by an class in this module, and then the overall 
  90     C{Config} class is a composition of the various other classes.   
  91   
  92     Any configuration section that is missing in the XML document (or has not 
  93     been filled into an "empty" document) will just be set to C{None} in the 
  94     object representation.  The same goes for individual fields within each 
  95     configuration section.  Keep in mind that the document might not be 
  96     completely valid if some sections or fields aren't filled in - but that 
  97     won't matter until validation takes place (see the I{Validation} section 
  98     below). 
  99   
 100  Unicode vs. String Data 
 101  ======================= 
 102   
 103     By default, all string data that comes out of XML documents in Python is 
 104     unicode data (i.e. C{u"whatever"}).  This is fine for many things, but when 
 105     it comes to filesystem paths, it can cause us some problems.  We really want 
 106     strings to be encoded in the filesystem encoding rather than being unicode. 
 107     So, most elements in configuration which represent filesystem paths are 
 108     coverted to plain strings using L{util.encodePath}.  The main exception is 
 109     the various C{absoluteExcludePath} and C{relativeExcludePath} lists.  These 
 110     are I{not} converted, because they are generally only used for filtering, 
 111     not for filesystem operations. 
 112   
 113  Validation  
 114  ========== 
 115   
 116     There are two main levels of validation in the C{Config} class and its 
 117     children.  The first is field-level validation.  Field-level validation 
 118     comes into play when a given field in an object is assigned to or updated. 
 119     We use Python's C{property} functionality to enforce specific validations on 
 120     field values, and in some places we even use customized list classes to 
 121     enforce validations on list members.  You should expect to catch a 
 122     C{ValueError} exception when making assignments to configuration class 
 123     fields. 
 124   
 125     The second level of validation is post-completion validation.  Certain 
 126     validations don't make sense until a document is fully "complete".  We don't 
 127     want these validations to apply all of the time, because it would make 
 128     building up a document from scratch a real pain.  For instance, we might 
 129     have to do things in the right order to keep from throwing exceptions, etc. 
 130   
 131     All of these post-completion validations are encapsulated in the 
 132     L{Config.validate} method.  This method can be called at any time by a 
 133     client, and will always be called immediately after creating a C{Config} 
 134     object from XML data and before exporting a C{Config} object to XML.  This 
 135     way, we get decent ease-of-use but we also don't accept or emit invalid 
 136     configuration files. 
 137   
 138     The L{Config.validate} implementation actually takes two passes to 
 139     completely validate a configuration document.  The first pass at validation 
 140     is to ensure that the proper sections are filled into the document.  There 
 141     are default requirements, but the caller has the opportunity to override 
 142     these defaults. 
 143   
 144     The second pass at validation ensures that any filled-in section contains 
 145     valid data.  Any section which is not set to C{None} is validated according 
 146     to the rules for that section (see below). 
 147   
 148     I{Reference Validations} 
 149   
 150     No validations. 
 151   
 152     I{Extensions Validations} 
 153   
 154     The list of actions may be either C{None} or an empty list C{[]} if desired. 
 155     Each extended action must include a name, a module and a function.  Then, an 
 156     extended action must include either an index or dependency information. 
 157     Which one is required depends on which order mode is configured. 
 158   
 159     I{Options Validations} 
 160   
 161     All fields must be filled in.  The rcp command is used as a default value 
 162     for all remote peers in the staging section.  Remote peers can also rely on 
 163     the backup user as the default remote user name if they choose. 
 164   
 165     I{Collect Validations} 
 166   
 167     The target directory must be filled in.  The collect mode, archive mode and 
 168     ignore file are all optional.  The list of absolute paths to exclude and 
 169     patterns to exclude may be either C{None} or an empty list C{[]} if desired. 
 170   
 171     Each collect directory entry must contain an absolute path to collect, and 
 172     then must either be able to take collect mode, archive mode and ignore file 
 173     configuration from the parent C{CollectConfig} object, or must set each 
 174     value on its own.  The list of absolute paths to exclude, relative paths to 
 175     exclude and patterns to exclude may be either C{None} or an empty list C{[]} 
 176     if desired.  Any list of absolute paths to exclude or patterns to exclude 
 177     will be combined with the same list in the C{CollectConfig} object to make 
 178     the complete list for a given directory. 
 179   
 180     I{Stage Validations} 
 181   
 182     The target directory must be filled in.  There must be at least one peer 
 183     (remote or local) between the two lists of peers.  A list with no entries 
 184     can be either C{None} or an empty list C{[]} if desired. 
 185   
 186     Local peers must be completely filled in, including both name and collect 
 187     directory.  Remote peers must also fill in the name and collect directory, 
 188     but can leave the remote user and rcp command unset.  In this case, the 
 189     remote user is assumed to match the backup user from the options section and 
 190     rcp command is taken directly from the options section. 
 191   
 192     I{Store Validations} 
 193   
 194     The device type and drive speed are optional, and all other values are 
 195     required (missing booleans will be set to defaults, which is OK). 
 196   
 197     The image writer functionality in the C{writer} module is supposed to be 
 198     able to handle a device speed of C{None}.  Any caller which needs a "real" 
 199     (non-C{None}) value for the device type can use C{DEFAULT_DEVICE_TYPE}, 
 200     which is guaranteed to be sensible. 
 201   
 202     I{Purge Validations} 
 203   
 204     The list of purge directories may be either C{None} or an empty list C{[]} 
 205     if desired.  All purge directories must contain a path and a retain days 
 206     value. 
 207   
 208  @sort: ActionDependencies, ActionHook, PreActionHook, PostActionHook, 
 209         ExtendedAction, CommandOverride, CollectFile, CollectDir, PurgeDir, LocalPeer,  
 210         RemotePeer, ReferenceConfig, ExtensionsConfig, OptionsConfig, 
 211         CollectConfig, StageConfig, StoreConfig, PurgeConfig, Config, 
 212         DEFAULT_DEVICE_TYPE, DEFAULT_MEDIA_TYPE,  
 213         VALID_DEVICE_TYPES, VALID_MEDIA_TYPES,  
 214         VALID_COLLECT_MODES, VALID_ARCHIVE_MODES, 
 215         VALID_ORDER_MODES 
 216   
 217  @var DEFAULT_DEVICE_TYPE: The default device type. 
 218  @var DEFAULT_MEDIA_TYPE: The default media type. 
 219  @var VALID_DEVICE_TYPES: List of valid device types. 
 220  @var VALID_MEDIA_TYPES: List of valid media types. 
 221  @var VALID_COLLECT_MODES: List of valid collect modes. 
 222  @var VALID_COMPRESS_MODES: List of valid compress modes. 
 223  @var VALID_ARCHIVE_MODES: List of valid archive modes. 
 224  @var VALID_ORDER_MODES: List of valid extension order modes. 
 225   
 226  @author: Kenneth J. Pronovici <pronovic@ieee.org> 
 227  """ 
 228   
 229  ######################################################################## 
 230  # Imported modules 
 231  ######################################################################## 
 232   
 233  # System modules 
 234  import os 
 235  import re 
 236  import logging 
 237   
 238  # Cedar Backup modules 
 239  from CedarBackup2.writers.util import validateScsiId, validateDriveSpeed 
 240  from CedarBackup2.util import UnorderedList, AbsolutePathList, ObjectTypeList 
 241  from CedarBackup2.util import RegexMatchList, RegexList, encodePath 
 242  from CedarBackup2.xmlutil import isElement, readChildren, readFirstChild 
 243  from CedarBackup2.xmlutil import readStringList, readString, readInteger, readBoolean 
 244  from CedarBackup2.xmlutil import addContainerNode, addStringNode, addIntegerNode, addBooleanNode 
 245  from CedarBackup2.xmlutil import createInputDom, createOutputDom, serializeDom 
 246   
 247   
 248  ######################################################################## 
 249  # Module-wide constants and variables 
 250  ######################################################################## 
 251   
 252  logger = logging.getLogger("CedarBackup2.log.config") 
 253   
 254  DEFAULT_DEVICE_TYPE   = "cdwriter" 
 255  DEFAULT_MEDIA_TYPE    = "cdrw-74" 
 256   
 257  VALID_DEVICE_TYPES    = [ "cdwriter", "dvdwriter", ] 
 258  VALID_CD_MEDIA_TYPES  = [ "cdr-74", "cdrw-74", "cdr-80", "cdrw-80", ] 
 259  VALID_DVD_MEDIA_TYPES = [ "dvd+r", "dvd+rw", ] 
 260  VALID_MEDIA_TYPES     = VALID_CD_MEDIA_TYPES + VALID_DVD_MEDIA_TYPES 
 261  VALID_COLLECT_MODES   = [ "daily", "weekly", "incr", ] 
 262  VALID_ARCHIVE_MODES   = [ "tar", "targz", "tarbz2", ] 
 263  VALID_COMPRESS_MODES  = [ "none", "gzip", "bzip2", ] 
 264  VALID_ORDER_MODES     = [ "index", "dependency", ] 
 265  VALID_BLANK_MODES     = [ "daily", "weekly", ] 
 266   
 267  REWRITABLE_MEDIA_TYPES = [ "cdrw-74", "cdrw-80", "dvd+rw", ] 
 268   
 269  ACTION_NAME_REGEX     = r"^[a-z0-9]*$" 
 270   
 271   
 272  ######################################################################## 
 273  # ActionDependencies class definition 
 274  ######################################################################## 
 275   
276 -class ActionDependencies(object):
277 278 """ 279 Class representing dependencies associated with an extended action. 280 281 Execution ordering for extended actions is done in one of two ways: either by using 282 index values (lower index gets run first) or by having the extended action specify 283 dependencies in terms of other named actions. This class encapsulates the dependency 284 information for an extended action. 285 286 As with all of the other classes that represent configuration sections, all 287 of these values are optional. It is up to some higher-level construct to 288 decide whether everything they need is filled in. Some validation is done 289 on non-C{None} assignments through the use of the Python C{property()} 290 construct. 291 292 The following restrictions exist on data in this class: 293 294 - Any action name must be a non-empty string matching C{ACTION_NAME_REGEX} 295 296 @sort: __init__, __repr__, __str__, __cmp__, action, command, before, after 297 """ 298
299 - def __init__(self, beforeList=None, afterList=None):
300 """ 301 Constructor for the C{ActionDependencies} class. 302 303 @param beforeList: List of named actions that this action must be run before 304 @param afterList: List of named actions that this action must be run after 305 306 @raise ValueError: If one of the values is invalid. 307 """ 308 self._beforeList = None 309 self._afterList = None 310 self.beforeList = beforeList 311 self.afterList = afterList
312
313 - def __repr__(self):
314 """ 315 Official string representation for class instance. 316 """ 317 return "ActionDependencies(%s, %s)" % (self.beforeList, self.afterList)
318
319 - def __str__(self):
320 """ 321 Informal string representation for class instance. 322 """ 323 return self.__repr__()
324
325 - def __cmp__(self, other):
326 """ 327 Definition of equals operator for this class. 328 @param other: Other object to compare to. 329 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 330 """ 331 if other is None: 332 return 1 333 if self._beforeList != other._beforeList: 334 if self._beforeList < other._beforeList: 335 return -1 336 else: 337 return 1 338 if self._afterList != other._afterList: 339 if self._afterList < other._afterList: 340 return -1 341 else: 342 return 1 343 return 0
344
345 - def _setBeforeList(self, value):
346 """ 347 Property target used to set the "run before" list. 348 Either the value must be C{None} or each element must be a string matching ACTION_NAME_REGEX. 349 @raise ValueError: If the value does not match the regular expression. 350 """ 351 if value is None: 352 self._beforeList = None 353 else: 354 try: 355 saved = self._beforeList 356 self._beforeList = RegexMatchList(ACTION_NAME_REGEX, emptyAllowed=False, prefix="Action name") 357 self._beforeList.extend(value) 358 except Exception, e: 359 self._beforeList = saved 360 raise e
361
362 - def _getBeforeList(self):
363 """ 364 Property target used to get the "run before" list. 365 """ 366 return self._beforeList
367
368 - def _setAfterList(self, value):
369 """ 370 Property target used to set the "run after" list. 371 Either the value must be C{None} or each element must be a string matching ACTION_NAME_REGEX. 372 @raise ValueError: If the value does not match the regular expression. 373 """ 374 if value is None: 375 self._afterList = None 376 else: 377 try: 378 saved = self._afterList 379 self._afterList = RegexMatchList(ACTION_NAME_REGEX, emptyAllowed=False, prefix="Action name") 380 self._afterList.extend(value) 381 except Exception, e: 382 self._afterList = saved 383 raise e
384
385 - def _getAfterList(self):
386 """ 387 Property target used to get the "run after" list. 388 """ 389 return self._afterList
390 391 beforeList = property(_getBeforeList, _setBeforeList, None, "List of named actions that this action must be run before.") 392 afterList = property(_getAfterList, _setAfterList, None, "List of named actions that this action must be run after.")
393 394 395 ######################################################################## 396 # ActionHook class definition 397 ######################################################################## 398
399 -class ActionHook(object):
400 401 """ 402 Class representing a hook associated with an action. 403 404 A hook associated with an action is a shell command to be executed either 405 before or after a named action is executed. 406 407 As with all of the other classes that represent configuration sections, all 408 of these values are optional. It is up to some higher-level construct to 409 decide whether everything they need is filled in. Some validation is done 410 on non-C{None} assignments through the use of the Python C{property()} 411 construct. 412 413 The following restrictions exist on data in this class: 414 415 - The action name must be a non-empty string matching C{ACTION_NAME_REGEX} 416 - The shell command must be a non-empty string. 417 418 The internal C{before} and C{after} instance variables are always set to 419 False in this parent class. 420 421 @sort: __init__, __repr__, __str__, __cmp__, action, command, before, after 422 """ 423
424 - def __init__(self, action=None, command=None):
425 """ 426 Constructor for the C{ActionHook} class. 427 428 @param action: Action this hook is associated with 429 @param command: Shell command to execute 430 431 @raise ValueError: If one of the values is invalid. 432 """ 433 self._action = None 434 self._command = None 435 self._before = False 436 self._after = False 437 self.action = action 438 self.command = command
439
440 - def __repr__(self):
441 """ 442 Official string representation for class instance. 443 """ 444 return "ActionHook(%s, %s, %s, %s)" % (self.action, self.command, self.before, self.after)
445
446 - def __str__(self):
447 """ 448 Informal string representation for class instance. 449 """ 450 return self.__repr__()
451
452 - def __cmp__(self, other):
453 """ 454 Definition of equals operator for this class. 455 @param other: Other object to compare to. 456 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 457 """ 458 if other is None: 459 return 1 460 if self._action != other._action: 461 if self._action < other._action: 462 return -1 463 else: 464 return 1 465 if self._command != other._command: 466 if self._command < other._command: 467 return -1 468 else: 469 return 1 470 if self._before != other._before: 471 if self._before < other._before: 472 return -1 473 else: 474 return 1 475 if self._after != other._after: 476 if self._after < other._after: 477 return -1 478 else: 479 return 1 480 return 0
481
482 - def _setAction(self, value):
483 """ 484 Property target used to set the action name. 485 The value must be a non-empty string if it is not C{None}. 486 It must also consist only of lower-case letters and digits. 487 @raise ValueError: If the value is an empty string. 488 """ 489 pattern = re.compile(ACTION_NAME_REGEX) 490 if value is not None: 491 if len(value) < 1: 492 raise ValueError("The action name must be a non-empty string.") 493 if not pattern.search(value): 494 raise ValueError("The action name must consist of only lower-case letters and digits.") 495 self._action = value
496
497 - def _getAction(self):
498 """ 499 Property target used to get the action name. 500 """ 501 return self._action
502
503 - def _setCommand(self, value):
504 """ 505 Property target used to set the command. 506 The value must be a non-empty string if it is not C{None}. 507 @raise ValueError: If the value is an empty string. 508 """ 509 if value is not None: 510 if len(value) < 1: 511 raise ValueError("The command must be a non-empty string.") 512 self._command = value
513
514 - def _getCommand(self):
515 """ 516 Property target used to get the command. 517 """ 518 return self._command
519
520 - def _getBefore(self):
521 """ 522 Property target used to get the before flag. 523 """ 524 return self._before
525
526 - def _getAfter(self):
527 """ 528 Property target used to get the after flag. 529 """ 530 return self._after
531 532 action = property(_getAction, _setAction, None, "Action this hook is associated with.") 533 command = property(_getCommand, _setCommand, None, "Shell command to execute.") 534 before = property(_getBefore, None, None, "Indicates whether command should be executed before action.") 535 after = property(_getAfter, None, None, "Indicates whether command should be executed after action.")
536
537 -class PreActionHook(ActionHook):
538 539 """ 540 Class representing a pre-action hook associated with an action. 541 542 A hook associated with an action is a shell command to be executed either 543 before or after a named action is executed. In this case, a pre-action hook 544 is executed before the named action. 545 546 As with all of the other classes that represent configuration sections, all 547 of these values are optional. It is up to some higher-level construct to 548 decide whether everything they need is filled in. Some validation is done 549 on non-C{None} assignments through the use of the Python C{property()} 550 construct. 551 552 The following restrictions exist on data in this class: 553 554 - The action name must be a non-empty string consisting of lower-case letters and digits. 555 - The shell command must be a non-empty string. 556 557 The internal C{before} instance variable is always set to True in this 558 class. 559 560 @sort: __init__, __repr__, __str__, __cmp__, action, command, before, after 561 """ 562
563 - def __init__(self, action=None, command=None):
564 """ 565 Constructor for the C{PreActionHook} class. 566 567 @param action: Action this hook is associated with 568 @param command: Shell command to execute 569 570 @raise ValueError: If one of the values is invalid. 571 """ 572 ActionHook.__init__(self, action, command) 573 self._before = True
574
575 - def __repr__(self):
576 """ 577 Official string representation for class instance. 578 """ 579 return "PreActionHook(%s, %s, %s, %s)" % (self.action, self.command, self.before, self.after)
580
581 -class PostActionHook(ActionHook):
582 583 """ 584 Class representing a pre-action hook associated with an action. 585 586 A hook associated with an action is a shell command to be executed either 587 before or after a named action is executed. In this case, a post-action hook 588 is executed after the named action. 589 590 As with all of the other classes that represent configuration sections, all 591 of these values are optional. It is up to some higher-level construct to 592 decide whether everything they need is filled in. Some validation is done 593 on non-C{None} assignments through the use of the Python C{property()} 594 construct. 595 596 The following restrictions exist on data in this class: 597 598 - The action name must be a non-empty string consisting of lower-case letters and digits. 599 - The shell command must be a non-empty string. 600 601 The internal C{before} instance variable is always set to True in this 602 class. 603 604 @sort: __init__, __repr__, __str__, __cmp__, action, command, before, after 605 """ 606
607 - def __init__(self, action=None, command=None):
608 """ 609 Constructor for the C{PostActionHook} class. 610 611 @param action: Action this hook is associated with 612 @param command: Shell command to execute 613 614 @raise ValueError: If one of the values is invalid. 615 """ 616 ActionHook.__init__(self, action, command) 617 self._after = True
618
619 - def __repr__(self):
620 """ 621 Official string representation for class instance. 622 """ 623 return "PostActionHook(%s, %s, %s, %s)" % (self.action, self.command, self.before, self.after)
624 625 626 ######################################################################## 627 # BlankBehavior class definition 628 ######################################################################## 629
630 -class BlankBehavior(object):
631 632 """ 633 Class representing optimized store-action media blanking behavior. 634 635 As with all of the other classes that represent configuration sections, all 636 of these values are optional. It is up to some higher-level construct to 637 decide whether everything they need is filled in. Some validation is done 638 on non-C{None} assignments through the use of the Python C{property()} 639 construct. 640 641 The following restrictions exist on data in this class: 642 643 - The blanking mode must be a one of the values in L{VALID_BLANK_MODES} 644 - The blanking factor must be a positive floating point number 645 646 @sort: __init__, __repr__, __str__, __cmp__, blankMode, blankFactor 647 """ 648
649 - def __init__(self, blankMode=None, blankFactor=None):
650 """ 651 Constructor for the C{BlankBehavior} class. 652 653 @param blankMode: Blanking mode 654 @param blankFactor: Blanking factor 655 656 @raise ValueError: If one of the values is invalid. 657 """ 658 self._blankMode = None 659 self._blankFactor = None 660 self.blankMode = blankMode 661 self.blankFactor = blankFactor
662
663 - def __repr__(self):
664 """ 665 Official string representation for class instance. 666 """ 667 return "BlankBehavior(%s, %s)" % (self.blankMode, self.blankFactor)
668
669 - def __str__(self):
670 """ 671 Informal string representation for class instance. 672 """ 673 return self.__repr__()
674
675 - def __cmp__(self, other):
676 """ 677 Definition of equals operator for this class. 678 @param other: Other object to compare to. 679 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 680 """ 681 if other is None: 682 return 1 683 if self._blankMode != other._blankMode: 684 if self._blankMode < other._blankMode: 685 return -1 686 else: 687 return 1 688 if self._blankFactor != other._blankFactor: 689 if self._blankFactor < other._blankFactor: 690 return -1 691 else: 692 return 1 693 return 0
694
695 - def _setBlankMode(self, value):
696 """ 697 Property target used to set the blanking mode. 698 The value must be one of L{VALID_BLANK_MODES}. 699 @raise ValueError: If the value is not valid. 700 """ 701 if value is not None: 702 if value not in VALID_BLANK_MODES: 703 raise ValueError("Blanking mode must be one of %s." % VALID_BLANK_MODES) 704 self._blankMode = value
705
706 - def _getBlankMode(self):
707 """ 708 Property target used to get the blanking mode. 709 """ 710 return self._blankMode
711
712 - def _setBlankFactor(self, value):
713 """ 714 Property target used to set the blanking factor. 715 The value must be a non-empty string if it is not C{None}. 716 @raise ValueError: If the value is an empty string. 717 @raise ValueError: If the value is not a valid floating point number 718 @raise ValueError: If the value is less than zero 719 """ 720 if value is not None: 721 if len(value) < 1: 722 raise ValueError("Blanking factor must be a non-empty string.") 723 floatValue = float(value) 724 if floatValue < 0.0: 725 raise ValueError("Blanking factor cannot be negative.") 726 self._blankFactor = value # keep around string
727
728 - def _getBlankFactor(self):
729 """ 730 Property target used to get the blanking factor. 731 """ 732 return self._blankFactor
733 734 blankMode = property(_getBlankMode, _setBlankMode, None, "Blanking mode") 735 blankFactor = property(_getBlankFactor, _setBlankFactor, None, "Blanking factor")
736 737 738 ######################################################################## 739 # ExtendedAction class definition 740 ######################################################################## 741
742 -class ExtendedAction(object):
743 744 """ 745 Class representing an extended action. 746 747 As with all of the other classes that represent configuration sections, all 748 of these values are optional. It is up to some higher-level construct to 749 decide whether everything they need is filled in. Some validation is done 750 on non-C{None} assignments through the use of the Python C{property()} 751 construct. 752 753 Essentially, an extended action needs to allow the following to happen:: 754 755 exec("from %s import %s" % (module, function)) 756 exec("%s(action, configPath")" % function) 757 758 The following restrictions exist on data in this class: 759 760 - The action name must be a non-empty string consisting of lower-case letters and digits. 761 - The module must be a non-empty string and a valid Python identifier. 762 - The function must be an on-empty string and a valid Python identifier. 763 - If set, the index must be a positive integer. 764 - If set, the dependencies attribute must be an C{ActionDependencies} object. 765 766 @sort: __init__, __repr__, __str__, __cmp__, name, module, function, index, dependencies 767 """ 768
769 - def __init__(self, name=None, module=None, function=None, index=None, dependencies=None):
770 """ 771 Constructor for the C{ExtendedAction} class. 772 773 @param name: Name of the extended action 774 @param module: Name of the module containing the extended action function 775 @param function: Name of the extended action function 776 @param index: Index of action, used for execution ordering 777 @param dependencies: Dependencies for action, used for execution ordering 778 779 @raise ValueError: If one of the values is invalid. 780 """ 781 self._name = None 782 self._module = None 783 self._function = None 784 self._index = None 785 self._dependencies = None 786 self.name = name 787 self.module = module 788 self.function = function 789 self.index = index 790 self.dependencies = dependencies
791
792 - def __repr__(self):
793 """ 794 Official string representation for class instance. 795 """ 796 return "ExtendedAction(%s, %s, %s, %s, %s)" % (self.name, self.module, self.function, self.index, self.dependencies)
797
798 - def __str__(self):
799 """ 800 Informal string representation for class instance. 801 """ 802 return self.__repr__()
803
804 - def __cmp__(self, other):
805 """ 806 Definition of equals operator for this class. 807 @param other: Other object to compare to. 808 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 809 """ 810 if other is None: 811 return 1 812 if self._name != other._name: 813 if self._name < other._name: 814 return -1 815 else: 816 return 1 817 if self._module != other._module: 818 if self._module < other._module: 819 return -1 820 else: 821 return 1 822 if self._function != other._function: 823 if self._function < other._function: 824 return -1 825 else: 826 return 1 827 if self._index != other._index: 828 if self._index < other._index: 829 return -1 830 else: 831 return 1 832 if self._dependencies != other._dependencies: 833 if self._dependencies < other._dependencies: 834 return -1 835 else: 836 return 1 837 return 0
838
839 - def _setName(self, value):
840 """ 841 Property target used to set the action name. 842 The value must be a non-empty string if it is not C{None}. 843 It must also consist only of lower-case letters and digits. 844 @raise ValueError: If the value is an empty string. 845 """ 846 pattern = re.compile(ACTION_NAME_REGEX) 847 if value is not None: 848 if len(value) < 1: 849 raise ValueError("The action name must be a non-empty string.") 850 if not pattern.search(value): 851 raise ValueError("The action name must consist of only lower-case letters and digits.") 852 self._name = value
853
854 - def _getName(self):
855 """ 856 Property target used to get the action name. 857 """ 858 return self._name
859
860 - def _setModule(self, value):
861 """ 862 Property target used to set the module name. 863 The value must be a non-empty string if it is not C{None}. 864 It must also be a valid Python identifier. 865 @raise ValueError: If the value is an empty string. 866 """ 867 pattern = re.compile(r"^([A-Za-z_][A-Za-z0-9_]*)(\.[A-Za-z_][A-Za-z0-9_]*)*$") 868 if value is not None: 869 if len(value) < 1: 870 raise ValueError("The module name must be a non-empty string.") 871 if not pattern.search(value): 872 raise ValueError("The module name must be a valid Python identifier.") 873 self._module = value
874
875 - def _getModule(self):
876 """ 877 Property target used to get the module name. 878 """ 879 return self._module
880
881 - def _setFunction(self, value):
882 """ 883 Property target used to set the function name. 884 The value must be a non-empty string if it is not C{None}. 885 It must also be a valid Python identifier. 886 @raise ValueError: If the value is an empty string. 887 """ 888 pattern = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$") 889 if value is not None: 890 if len(value) < 1: 891 raise ValueError("The function name must be a non-empty string.") 892 if not pattern.search(value): 893 raise ValueError("The function name must be a valid Python identifier.") 894 self._function = value
895
896 - def _getFunction(self):
897 """ 898 Property target used to get the function name. 899 """ 900 return self._function
901
902 - def _setIndex(self, value):
903 """ 904 Property target used to set the action index. 905 The value must be an integer >= 0. 906 @raise ValueError: If the value is not valid. 907 """ 908 if value is None: 909 self._index = None 910 else: 911 try: 912 value = int(value) 913 except TypeError: 914 raise ValueError("Action index value must be an integer >= 0.") 915 if value < 0: 916 raise ValueError("Action index value must be an integer >= 0.") 917 self._index = value
918
919 - def _getIndex(self):
920 """ 921 Property target used to get the action index. 922 """ 923 return self._index
924
925 - def _setDependencies(self, value):
926 """ 927 Property target used to set the action dependencies information. 928 If not C{None}, the value must be a C{ActionDependecies} object. 929 @raise ValueError: If the value is not a C{ActionDependencies} object. 930 """ 931 if value is None: 932 self._dependencies = None 933 else: 934 if not isinstance(value, ActionDependencies): 935 raise ValueError("Value must be a C{ActionDependencies} object.") 936 self._dependencies = value
937
938 - def _getDependencies(self):
939 """ 940 Property target used to get action dependencies information. 941 """ 942 return self._dependencies
943 944 name = property(_getName, _setName, None, "Name of the extended action.") 945 module = property(_getModule, _setModule, None, "Name of the module containing the extended action function.") 946 function = property(_getFunction, _setFunction, None, "Name of the extended action function.") 947 index = property(_getIndex, _setIndex, None, "Index of action, used for execution ordering.") 948 dependencies = property(_getDependencies, _setDependencies, None, "Dependencies for action, used for execution ordering.")
949 950 951 ######################################################################## 952 # CommandOverride class definition 953 ######################################################################## 954
955 -class CommandOverride(object):
956 957 """ 958 Class representing a piece of Cedar Backup command override configuration. 959 960 As with all of the other classes that represent configuration sections, all 961 of these values are optional. It is up to some higher-level construct to 962 decide whether everything they need is filled in. Some validation is done 963 on non-C{None} assignments through the use of the Python C{property()} 964 construct. 965 966 The following restrictions exist on data in this class: 967 968 - The absolute path must be absolute 969 970 @note: Lists within this class are "unordered" for equality comparisons. 971 972 @sort: __init__, __repr__, __str__, __cmp__, command, absolutePath 973 """ 974
975 - def __init__(self, command=None, absolutePath=None):
976 """ 977 Constructor for the C{CommandOverride} class. 978 979 @param command: Name of command to be overridden. 980 @param absolutePath: Absolute path of the overrridden command. 981 982 @raise ValueError: If one of the values is invalid. 983 """ 984 self._command = None 985 self._absolutePath = None 986 self.command = command 987 self.absolutePath = absolutePath
988
989 - def __repr__(self):
990 """ 991 Official string representation for class instance. 992 """ 993 return "CommandOverride(%s, %s)" % (self.command, self.absolutePath)
994
995 - def __str__(self):
996 """ 997 Informal string representation for class instance. 998 """ 999 return self.__repr__()
1000
1001 - def __cmp__(self, other):
1002 """ 1003 Definition of equals operator for this class. 1004 @param other: Other object to compare to. 1005 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 1006 """ 1007 if other is None: 1008 return 1 1009 if self._command != other._command: 1010 if self._command < other.command: 1011 return -1 1012 else: 1013 return 1 1014 if self._absolutePath != other._absolutePath: 1015 if self._absolutePath < other.absolutePath: 1016 return -1 1017 else: 1018 return 1 1019 return 0
1020
1021 - def _setCommand(self, value):
1022 """ 1023 Property target used to set the command. 1024 The value must be a non-empty string if it is not C{None}. 1025 @raise ValueError: If the value is an empty string. 1026 """ 1027 if value is not None: 1028 if len(value) < 1: 1029 raise ValueError("The command must be a non-empty string.") 1030 self._command = value
1031
1032 - def _getCommand(self):
1033 """ 1034 Property target used to get the command. 1035 """ 1036 return self._command
1037
1038 - def _setAbsolutePath(self, value):
1039 """ 1040 Property target used to set the absolute path. 1041 The value must be an absolute path if it is not C{None}. 1042 It does not have to exist on disk at the time of assignment. 1043 @raise ValueError: If the value is not an absolute path. 1044 @raise ValueError: If the value cannot be encoded properly. 1045 """ 1046 if value is not None: 1047 if not os.path.isabs(value): 1048 raise ValueError("Not an absolute path: [%s]" % value) 1049 self._absolutePath = encodePath(value)
1050
1051 - def _getAbsolutePath(self):
1052 """ 1053 Property target used to get the absolute path. 1054 """ 1055 return self._absolutePath
1056 1057 command = property(_getCommand, _setCommand, None, doc="Name of command to be overridden.") 1058 absolutePath = property(_getAbsolutePath, _setAbsolutePath, None, doc="Absolute path of the overrridden command.")
1059 1060 1061 ######################################################################## 1062 # CollectFile class definition 1063 ######################################################################## 1064
1065 -class CollectFile(object):
1066 1067 """ 1068 Class representing a Cedar Backup collect file. 1069 1070 As with all of the other classes that represent configuration sections, all 1071 of these values are optional. It is up to some higher-level construct to 1072 decide whether everything they need is filled in. Some validation is done 1073 on non-C{None} assignments through the use of the Python C{property()} 1074 construct. 1075 1076 The following restrictions exist on data in this class: 1077 1078 - Absolute paths must be absolute 1079 - The collect mode must be one of the values in L{VALID_COLLECT_MODES}. 1080 - The archive mode must be one of the values in L{VALID_ARCHIVE_MODES}. 1081 1082 @sort: __init__, __repr__, __str__, __cmp__, absolutePath, collectMode, archiveMode 1083 """ 1084
1085 - def __init__(self, absolutePath=None, collectMode=None, archiveMode=None):
1086 """ 1087 Constructor for the C{CollectFile} class. 1088 1089 @param absolutePath: Absolute path of the file to collect. 1090 @param collectMode: Overridden collect mode for this file. 1091 @param archiveMode: Overridden archive mode for this file. 1092 1093 @raise ValueError: If one of the values is invalid. 1094 """ 1095 self._absolutePath = None 1096 self._collectMode = None 1097 self._archiveMode = None 1098 self.absolutePath = absolutePath 1099 self.collectMode = collectMode 1100 self.archiveMode = archiveMode
1101
1102 - def __repr__(self):
1103 """ 1104 Official string representation for class instance. 1105 """ 1106 return "CollectFile(%s, %s, %s)" % (self.absolutePath, self.collectMode, self.archiveMode)
1107
1108 - def __str__(self):
1109 """ 1110 Informal string representation for class instance. 1111 """ 1112 return self.__repr__()
1113
1114 - def __cmp__(self, other):
1115 """ 1116 Definition of equals operator for this class. 1117 @param other: Other object to compare to. 1118 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 1119 """ 1120 if other is None: 1121 return 1 1122 if self._absolutePath != other._absolutePath: 1123 if self._absolutePath < other.absolutePath: 1124 return -1 1125 else: 1126 return 1 1127 if self._collectMode != other._collectMode: 1128 if self._collectMode < other._collectMode: 1129 return -1 1130 else: 1131 return 1 1132 if self._archiveMode != other._archiveMode: 1133 if self._archiveMode < other._archiveMode: 1134 return -1 1135 else: 1136 return 1 1137 return 0
1138
1139 - def _setAbsolutePath(self, value):
1140 """ 1141 Property target used to set the absolute path. 1142 The value must be an absolute path if it is not C{None}. 1143 It does not have to exist on disk at the time of assignment. 1144 @raise ValueError: If the value is not an absolute path. 1145 @raise ValueError: If the value cannot be encoded properly. 1146 """ 1147 if value is not None: 1148 if not os.path.isabs(value): 1149 raise ValueError("Not an absolute path: [%s]" % value) 1150 self._absolutePath = encodePath(value)
1151
1152 - def _getAbsolutePath(self):
1153 """ 1154 Property target used to get the absolute path. 1155 """ 1156 return self._absolutePath
1157
1158 - def _setCollectMode(self, value):
1159 """ 1160 Property target used to set the collect mode. 1161 If not C{None}, the mode must be one of the values in L{VALID_COLLECT_MODES}. 1162 @raise ValueError: If the value is not valid. 1163 """ 1164 if value is not None: 1165 if value not in VALID_COLLECT_MODES: 1166 raise ValueError("Collect mode must be one of %s." % VALID_COLLECT_MODES) 1167 self._collectMode = value
1168
1169 - def _getCollectMode(self):
1170 """ 1171 Property target used to get the collect mode. 1172 """ 1173 return self._collectMode
1174
1175 - def _setArchiveMode(self, value):
1176 """ 1177 Property target used to set the archive mode. 1178 If not C{None}, the mode must be one of the values in L{VALID_ARCHIVE_MODES}. 1179 @raise ValueError: If the value is not valid. 1180 """ 1181 if value is not None: 1182 if value not in VALID_ARCHIVE_MODES: 1183 raise ValueError("Archive mode must be one of %s." % VALID_ARCHIVE_MODES) 1184 self._archiveMode = value
1185
1186 - def _getArchiveMode(self):
1187 """ 1188 Property target used to get the archive mode. 1189 """ 1190 return self._archiveMode
1191 1192 absolutePath = property(_getAbsolutePath, _setAbsolutePath, None, doc="Absolute path of the file to collect.") 1193 collectMode = property(_getCollectMode, _setCollectMode, None, doc="Overridden collect mode for this file.") 1194 archiveMode = property(_getArchiveMode, _setArchiveMode, None, doc="Overridden archive mode for this file.")
1195 1196 1197 ######################################################################## 1198 # CollectDir class definition 1199 ######################################################################## 1200
1201 -class CollectDir(object):
1202 1203 """ 1204 Class representing a Cedar Backup collect directory. 1205 1206 As with all of the other classes that represent configuration sections, all 1207 of these values are optional. It is up to some higher-level construct to 1208 decide whether everything they need is filled in. Some validation is done 1209 on non-C{None} assignments through the use of the Python C{property()} 1210 construct. 1211 1212 The following restrictions exist on data in this class: 1213 1214 - Absolute paths must be absolute 1215 - The collect mode must be one of the values in L{VALID_COLLECT_MODES}. 1216 - The archive mode must be one of the values in L{VALID_ARCHIVE_MODES}. 1217 - The ignore file must be a non-empty string. 1218 1219 For the C{absoluteExcludePaths} list, validation is accomplished through the 1220 L{util.AbsolutePathList} list implementation that overrides common list 1221 methods and transparently does the absolute path validation for us. 1222 1223 @note: Lists within this class are "unordered" for equality comparisons. 1224 1225 @sort: __init__, __repr__, __str__, __cmp__, absolutePath, collectMode, 1226 archiveMode, ignoreFile, absoluteExcludePaths, relativeExcludePaths, 1227 excludePatterns 1228 """ 1229
1230 - def __init__(self, absolutePath=None, collectMode=None, archiveMode=None, ignoreFile=None, 1231 absoluteExcludePaths=None, relativeExcludePaths=None, excludePatterns=None):
1232 """ 1233 Constructor for the C{CollectDir} class. 1234 1235 @param absolutePath: Absolute path of the directory to collect. 1236 @param collectMode: Overridden collect mode for this directory. 1237 @param archiveMode: Overridden archive mode for this directory. 1238 @param ignoreFile: Overidden ignore file name for this directory. 1239 @param absoluteExcludePaths: List of absolute paths to exclude. 1240 @param relativeExcludePaths: List of relative paths to exclude. 1241 @param excludePatterns: List of regular expression patterns to exclude. 1242 1243 @raise ValueError: If one of the values is invalid. 1244 """ 1245 self._absolutePath = None 1246 self._collectMode = None 1247 self._archiveMode = None 1248 self._ignoreFile = None 1249 self._absoluteExcludePaths = None 1250 self._relativeExcludePaths = None 1251 self._excludePatterns = None 1252 self.absolutePath = absolutePath 1253 self.collectMode = collectMode 1254 self.archiveMode = archiveMode 1255 self.ignoreFile = ignoreFile 1256 self.absoluteExcludePaths = absoluteExcludePaths 1257 self.relativeExcludePaths = relativeExcludePaths 1258 self.excludePatterns = excludePatterns
1259
1260 - def __repr__(self):
1261 """ 1262 Official string representation for class instance. 1263 """ 1264 return "CollectDir(%s, %s, %s, %s, %s, %s, %s)" % (self.absolutePath, self.collectMode, 1265 self.archiveMode, self.ignoreFile, 1266 self.absoluteExcludePaths, 1267 self.relativeExcludePaths, 1268 self.excludePatterns)
1269
1270 - def __str__(self):
1271 """ 1272 Informal string representation for class instance. 1273 """ 1274 return self.__repr__()
1275
1276 - def __cmp__(self, other):
1277 """ 1278 Definition of equals operator for this class. 1279 Lists within this class are "unordered" for equality comparisons. 1280 @param other: Other object to compare to. 1281 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 1282 """ 1283 if other is None: 1284 return 1 1285 if self._absolutePath != other._absolutePath: 1286 if self._absolutePath < other.absolutePath: 1287 return -1 1288 else: 1289 return 1 1290 if self._collectMode != other._collectMode: 1291 if self._collectMode < other._collectMode: 1292 return -1 1293 else: 1294 return 1 1295 if self._archiveMode != other._archiveMode: 1296 if self._archiveMode < other._archiveMode: 1297 return -1 1298 else: 1299 return 1 1300 if self._ignoreFile != other._ignoreFile: 1301 if self._ignoreFile < other._ignoreFile: 1302 return -1 1303 else: 1304 return 1 1305 if self._absoluteExcludePaths != other._absoluteExcludePaths: 1306 if self._absoluteExcludePaths < other._absoluteExcludePaths: 1307 return -1 1308 else: 1309 return 1 1310 if self._relativeExcludePaths != other._relativeExcludePaths: 1311 if self._relativeExcludePaths < other._relativeExcludePaths: 1312 return -1 1313 else: 1314 return 1 1315 if self._excludePatterns != other._excludePatterns: 1316 if self._excludePatterns < other._excludePatterns: 1317 return -1 1318 else: 1319 return 1 1320 return 0
1321
1322 - def _setAbsolutePath(self, value):
1323 """ 1324 Property target used to set the absolute path. 1325 The value must be an absolute path if it is not C{None}. 1326 It does not have to exist on disk at the time of assignment. 1327 @raise ValueError: If the value is not an absolute path. 1328 @raise ValueError: If the value cannot be encoded properly. 1329 """ 1330 if value is not None: 1331 if not os.path.isabs(value): 1332 raise ValueError("Not an absolute path: [%s]" % value) 1333 self._absolutePath = encodePath(value)
1334
1335 - def _getAbsolutePath(self):
1336 """ 1337 Property target used to get the absolute path. 1338 """ 1339 return self._absolutePath
1340
1341 - def _setCollectMode(self, value):
1342 """ 1343 Property target used to set the collect mode. 1344 If not C{None}, the mode must be one of the values in L{VALID_COLLECT_MODES}. 1345 @raise ValueError: If the value is not valid. 1346 """ 1347 if value is not None: 1348 if value not in VALID_COLLECT_MODES: 1349 raise ValueError("Collect mode must be one of %s." % VALID_COLLECT_MODES) 1350 self._collectMode = value
1351
1352 - def _getCollectMode(self):
1353 """ 1354 Property target used to get the collect mode. 1355 """ 1356 return self._collectMode
1357
1358 - def _setArchiveMode(self, value):
1359 """ 1360 Property target used to set the archive mode. 1361 If not C{None}, the mode must be one of the values in L{VALID_ARCHIVE_MODES}. 1362 @raise ValueError: If the value is not valid. 1363 """ 1364 if value is not None: 1365 if value not in VALID_ARCHIVE_MODES: 1366 raise ValueError("Archive mode must be one of %s." % VALID_ARCHIVE_MODES) 1367 self._archiveMode = value
1368
1369 - def _getArchiveMode(self):
1370 """ 1371 Property target used to get the archive mode. 1372 """ 1373 return self._archiveMode
1374
1375 - def _setIgnoreFile(self, value):
1376 """ 1377 Property target used to set the ignore file. 1378 The value must be a non-empty string if it is not C{None}. 1379 @raise ValueError: If the value is an empty string. 1380 """ 1381 if value is not None: 1382 if len(value) < 1: 1383 raise ValueError("The ignore file must be a non-empty string.") 1384 self._ignoreFile = value
1385
1386 - def _getIgnoreFile(self):
1387 """ 1388 Property target used to get the ignore file. 1389 """ 1390 return self._ignoreFile
1391
1392 - def _setAbsoluteExcludePaths(self, value):
1393 """ 1394 Property target used to set the absolute exclude paths list. 1395 Either the value must be C{None} or each element must be an absolute path. 1396 Elements do not have to exist on disk at the time of assignment. 1397 @raise ValueError: If the value is not an absolute path. 1398 """ 1399 if value is None: 1400 self._absoluteExcludePaths = None 1401 else: 1402 try: 1403 saved = self._absoluteExcludePaths 1404 self._absoluteExcludePaths = AbsolutePathList() 1405 self._absoluteExcludePaths.extend(value) 1406 except Exception, e: 1407 self._absoluteExcludePaths = saved 1408 raise e
1409
1410 - def _getAbsoluteExcludePaths(self):
1411 """ 1412 Property target used to get the absolute exclude paths list. 1413 """ 1414 return self._absoluteExcludePaths
1415
1416 - def _setRelativeExcludePaths(self, value):
1417 """ 1418 Property target used to set the relative exclude paths list. 1419 Elements do not have to exist on disk at the time of assignment. 1420 """ 1421 if value is None: 1422 self._relativeExcludePaths = None 1423 else: 1424 try: 1425 saved = self._relativeExcludePaths 1426 self._relativeExcludePaths = UnorderedList() 1427 self._relativeExcludePaths.extend(value) 1428 except Exception, e: 1429 self._relativeExcludePaths = saved 1430 raise e
1431
1432 - def _getRelativeExcludePaths(self):
1433 """ 1434 Property target used to get the relative exclude paths list. 1435 """ 1436 return self._relativeExcludePaths
1437
1438 - def _setExcludePatterns(self, value):
1439 """ 1440 Property target used to set the exclude patterns list. 1441 """ 1442 if value is None: 1443 self._excludePatterns = None 1444 else: 1445 try: 1446 saved = self._excludePatterns 1447 self._excludePatterns = RegexList() 1448 self._excludePatterns.extend(value) 1449 except Exception, e: 1450 self._excludePatterns = saved 1451 raise e
1452
1453 - def _getExcludePatterns(self):
1454 """ 1455 Property target used to get the exclude patterns list. 1456 """ 1457 return self._excludePatterns
1458 1459 absolutePath = property(_getAbsolutePath, _setAbsolutePath, None, doc="Absolute path of the directory to collect.") 1460 collectMode = property(_getCollectMode, _setCollectMode, None, doc="Overridden collect mode for this directory.") 1461 archiveMode = property(_getArchiveMode, _setArchiveMode, None, doc="Overridden archive mode for this directory.") 1462 ignoreFile = property(_getIgnoreFile, _setIgnoreFile, None, doc="Overridden ignore file name for this directory.") 1463 absoluteExcludePaths = property(_getAbsoluteExcludePaths, _setAbsoluteExcludePaths, None, "List of absolute paths to exclude.") 1464 relativeExcludePaths = property(_getRelativeExcludePaths, _setRelativeExcludePaths, None, "List of relative paths to exclude.") 1465 excludePatterns = property(_getExcludePatterns, _setExcludePatterns, None, "List of regular expression patterns to exclude.")
1466 1467 1468 ######################################################################## 1469 # PurgeDir class definition 1470 ######################################################################## 1471
1472 -class PurgeDir(object):
1473 1474 """ 1475 Class representing a Cedar Backup purge directory. 1476 1477 As with all of the other classes that represent configuration sections, all 1478 of these values are optional. It is up to some higher-level construct to 1479 decide whether everything they need is filled in. Some validation is done 1480 on non-C{None} assignments through the use of the Python C{property()} 1481 construct. 1482 1483 The following restrictions exist on data in this class: 1484 1485 - The absolute path must be an absolute path 1486 - The retain days value must be an integer >= 0. 1487 1488 @sort: __init__, __repr__, __str__, __cmp__, absolutePath, retainDays 1489 """ 1490
1491 - def __init__(self, absolutePath=None, retainDays=None):
1492 """ 1493 Constructor for the C{PurgeDir} class. 1494 1495 @param absolutePath: Absolute path of the directory to be purged. 1496 @param retainDays: Number of days content within directory should be retained. 1497 1498 @raise ValueError: If one of the values is invalid. 1499 """ 1500 self._absolutePath = None 1501 self._retainDays = None 1502 self.absolutePath = absolutePath 1503 self.retainDays = retainDays
1504
1505 - def __repr__(self):
1506 """ 1507 Official string representation for class instance. 1508 """ 1509 return "PurgeDir(%s, %s)" % (self.absolutePath, self.retainDays)
1510
1511 - def __str__(self):
1512 """ 1513 Informal string representation for class instance. 1514 """ 1515 return self.__repr__()
1516
1517 - def __cmp__(self, other):
1518 """ 1519 Definition of equals operator for this class. 1520 @param other: Other object to compare to. 1521 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 1522 """ 1523 if other is None: 1524 return 1 1525 if self._absolutePath != other._absolutePath: 1526 if self._absolutePath < other._absolutePath: 1527 return -1 1528 else: 1529 return 1 1530 if self._retainDays != other._retainDays: 1531 if self._retainDays < other._retainDays: 1532 return -1 1533 else: 1534 return 1 1535 return 0
1536
1537 - def _setAbsolutePath(self, value):
1538 """ 1539 Property target used to set the absolute path. 1540 The value must be an absolute path if it is not C{None}. 1541 It does not have to exist on disk at the time of assignment. 1542 @raise ValueError: If the value is not an absolute path. 1543 @raise ValueError: If the value cannot be encoded properly. 1544 """ 1545 if value is not None: 1546 if not os.path.isabs(value): 1547 raise ValueError("Absolute path must, er, be an absolute path.") 1548 self._absolutePath = encodePath(value)
1549
1550 - def _getAbsolutePath(self):
1551 """ 1552 Property target used to get the absolute path. 1553 """ 1554 return self._absolutePath
1555
1556 - def _setRetainDays(self, value):
1557 """ 1558 Property target used to set the retain days value. 1559 The value must be an integer >= 0. 1560 @raise ValueError: If the value is not valid. 1561 """ 1562 if value is None: 1563 self._retainDays = None 1564 else: 1565 try: 1566 value = int(value) 1567 except TypeError: 1568 raise ValueError("Retain days value must be an integer >= 0.") 1569 if value < 0: 1570 raise ValueError("Retain days value must be an integer >= 0.") 1571 self._retainDays = value
1572
1573 - def _getRetainDays(self):
1574 """ 1575 Property target used to get the absolute path. 1576 """ 1577 return self._retainDays
1578 1579 absolutePath = property(_getAbsolutePath, _setAbsolutePath, None, "Absolute path of directory to purge.") 1580 retainDays = property(_getRetainDays, _setRetainDays, None, "Number of days content within directory should be retained.")
1581 1582 1583 ######################################################################## 1584 # LocalPeer class definition 1585 ######################################################################## 1586
1587 -class LocalPeer(object):
1588 1589 """ 1590 Class representing a Cedar Backup peer. 1591 1592 As with all of the other classes that represent configuration sections, all 1593 of these values are optional. It is up to some higher-level construct to 1594 decide whether everything they need is filled in. Some validation is done 1595 on non-C{None} assignments through the use of the Python C{property()} 1596 construct. 1597 1598 The following restrictions exist on data in this class: 1599 1600 - The peer name must be a non-empty string. 1601 - The collect directory must be an absolute path. 1602 1603 @sort: __init__, __repr__, __str__, __cmp__, name, collectDir 1604 """ 1605
1606 - def __init__(self, name=None, collectDir=None):
1607 """ 1608 Constructor for the C{LocalPeer} class. 1609 1610 @param name: Name of the peer, typically a valid hostname. 1611 @param collectDir: Collect directory to stage files from on peer. 1612 1613 @raise ValueError: If one of the values is invalid. 1614 """ 1615 self._name = None 1616 self._collectDir = None 1617 self.name = name 1618 self.collectDir = collectDir
1619
1620 - def __repr__(self):
1621 """ 1622 Official string representation for class instance. 1623 """ 1624 return "LocalPeer(%s, %s)" % (self.name, self.collectDir)
1625
1626 - def __str__(self):
1627 """ 1628 Informal string representation for class instance. 1629 """ 1630 return self.__repr__()
1631
1632 - def __cmp__(self, other):
1633 """ 1634 Definition of equals operator for this class. 1635 @param other: Other object to compare to. 1636 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 1637 """ 1638 if other is None: 1639 return 1 1640 if self._name != other._name: 1641 if self._name < other._name: 1642 return -1 1643 else: 1644 return 1 1645 if self._collectDir != other._collectDir: 1646 if self._collectDir < other._collectDir: 1647 return -1 1648 else: 1649 return 1 1650 return 0
1651
1652 - def _setName(self, value):
1653 """ 1654 Property target used to set the peer name. 1655 The value must be a non-empty string if it is not C{None}. 1656 @raise ValueError: If the value is an empty string. 1657 """ 1658 if value is not None: 1659 if len(value) < 1: 1660 raise ValueError("The peer name must be a non-empty string.") 1661 self._name = value
1662
1663 - def _getName(self):
1664 """ 1665 Property target used to get the peer name. 1666 """ 1667 return self._name
1668
1669 - def _setCollectDir(self, value):
1670 """ 1671 Property target used to set the collect directory. 1672 The value must be an absolute path if it is not C{None}. 1673 It does not have to exist on disk at the time of assignment. 1674 @raise ValueError: If the value is not an absolute path. 1675 @raise ValueError: If the value cannot be encoded properly. 1676 """ 1677 if value is not None: 1678 if not os.path.isabs(value): 1679 raise ValueError("Collect directory must be an absolute path.") 1680 self._collectDir = encodePath(value)
1681
1682 - def _getCollectDir(self):
1683 """ 1684 Property target used to get the collect directory. 1685 """ 1686 return self._collectDir
1687 1688 name = property(_getName, _setName, None, "Name of the peer, typically a valid hostname.") 1689 collectDir = property(_getCollectDir, _setCollectDir, None, "Collect directory to stage files from on peer.")
1690 1691 1692 ######################################################################## 1693 # RemotePeer class definition 1694 ######################################################################## 1695
1696 -class RemotePeer(object):
1697 1698 """ 1699 Class representing a Cedar Backup peer. 1700 1701 As with all of the other classes that represent configuration sections, all 1702 of these values are optional. It is up to some higher-level construct to 1703 decide whether everything they need is filled in. Some validation is done 1704 on non-C{None} assignments through the use of the Python C{property()} 1705 construct. 1706 1707 The following restrictions exist on data in this class: 1708 1709 - The peer name must be a non-empty string. 1710 - The collect directory must be an absolute path. 1711 - The remote user must be a non-empty string. 1712 - The rcp command must be a non-empty string. 1713 1714 @sort: __init__, __repr__, __str__, __cmp__, name, collectDir, remoteUser, rcpCommand 1715 """ 1716
1717 - def __init__(self, name=None, collectDir=None, remoteUser=None, rcpCommand=None):
1718 """ 1719 Constructor for the C{RemotePeer} class. 1720 1721 @param name: Name of the peer, must be a valid hostname. 1722 @param collectDir: Collect directory to stage files from on peer. 1723 @param remoteUser: Name of backup user on remote peer. 1724 @param rcpCommand: Overridden rcp-compatible copy command for peer. 1725 1726 @raise ValueError: If one of the values is invalid. 1727 """ 1728 self._name = None 1729 self._collectDir = None 1730 self._remoteUser = None 1731 self._rcpCommand = None 1732 self.name = name 1733 self.collectDir = collectDir 1734 self.remoteUser = remoteUser 1735 self.rcpCommand = rcpCommand
1736
1737 - def __repr__(self):
1738 """ 1739 Official string representation for class instance. 1740 """ 1741 return "RemotePeer(%s, %s, %s, %s)" % (self.name, self.collectDir, self.remoteUser, self.rcpCommand)
1742
1743 - def __str__(self):
1744 """ 1745 Informal string representation for class instance. 1746 """ 1747 return self.__repr__()
1748
1749 - def __cmp__(self, other):
1750 """ 1751 Definition of equals operator for this class. 1752 @param other: Other object to compare to. 1753 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 1754 """ 1755 if other is None: 1756 return 1 1757 if self._name != other._name: 1758 if self._name < other._name: 1759 return -1 1760 else: 1761 return 1 1762 if self._collectDir != other._collectDir: 1763 if self._collectDir < other._collectDir: 1764 return -1 1765 else: 1766 return 1 1767 if self._remoteUser != other._remoteUser: 1768 if self._remoteUser < other._remoteUser: 1769 return -1 1770 else: 1771 return 1 1772 if self._rcpCommand != other._rcpCommand: 1773 if self._rcpCommand < other._rcpCommand: 1774 return -1 1775 else: 1776 return 1 1777 return 0
1778
1779 - def _setName(self, value):
1780 """ 1781 Property target used to set the peer name. 1782 The value must be a non-empty string if it is not C{None}. 1783 @raise ValueError: If the value is an empty string. 1784 """ 1785 if value is not None: 1786 if len(value) < 1: 1787 raise ValueError("The peer name must be a non-empty string.") 1788 self._name = value
1789
1790 - def _getName(self):
1791 """ 1792 Property target used to get the peer name. 1793 """ 1794 return self._name
1795
1796 - def _setCollectDir(self, value):
1797 """ 1798 Property target used to set the collect directory. 1799 The value must be an absolute path if it is not C{None}. 1800 It does not have to exist on disk at the time of assignment. 1801 @raise ValueError: If the value is not an absolute path. 1802 @raise ValueError: If the value cannot be encoded properly. 1803 """ 1804 if value is not None: 1805 if not os.path.isabs(value): 1806 raise ValueError("Collect directory must be an absolute path.") 1807 self._collectDir = encodePath(value)
1808
1809 - def _getCollectDir(self):
1810 """ 1811 Property target used to get the collect directory. 1812 """ 1813 return self._collectDir
1814
1815 - def _setRemoteUser(self, value):
1816 """ 1817 Property target used to set the remote user. 1818 The value must be a non-empty string if it is not C{None}. 1819 @raise ValueError: If the value is an empty string. 1820 """ 1821 if value is not None: 1822 if len(value) < 1: 1823 raise ValueError("The remote user must be a non-empty string.") 1824 self._remoteUser = value
1825
1826 - def _getRemoteUser(self):
1827 """ 1828 Property target used to get the remote user. 1829 """ 1830 return self._remoteUser
1831
1832 - def _setRcpCommand(self, value):
1833 """ 1834 Property target used to set the rcp command. 1835 The value must be a non-empty string if it is not C{None}. 1836 @raise ValueError: If the value is an empty string. 1837 """ 1838 if value is not None: 1839 if len(value) < 1: 1840 raise ValueError("The remote user must be a non-empty string.") 1841 self._rcpCommand = value
1842
1843 - def _getRcpCommand(self):
1844 """ 1845 Property target used to get the rcp command. 1846 """ 1847 return self._rcpCommand
1848 1849 name = property(_getName, _setName, None, "Name of the peer, must be a valid hostname.") 1850 collectDir = property(_getCollectDir, _setCollectDir, None, "Collect directory to stage files from on peer.") 1851 remoteUser = property(_getRemoteUser, _setRemoteUser, None, "Name of backup user on remote peer.") 1852 rcpCommand = property(_getRcpCommand, _setRcpCommand, None, "Overridden rcp-compatible copy command for peer.")
1853 1854 1855 ######################################################################## 1856 # ReferenceConfig class definition 1857 ######################################################################## 1858
1859 -class ReferenceConfig(object):
1860 1861 """ 1862 Class representing a Cedar Backup reference configuration. 1863 1864 The reference information is just used for saving off metadata about 1865 configuration and exists mostly for backwards-compatibility with Cedar 1866 Backup 1.x. 1867 1868 As with all of the other classes that represent configuration sections, all 1869 of these values are optional. It is up to some higher-level construct to 1870 decide whether everything they need is filled in. We don't do any 1871 validation on the contents of any of the fields, although we generally 1872 expect them to be strings. 1873 1874 @sort: __init__, __repr__, __str__, __cmp__, author, revision, description, generator 1875 """ 1876
1877 - def __init__(self, author=None, revision=None, description=None, generator=None):
1878 """ 1879 Constructor for the C{ReferenceConfig} class. 1880 1881 @param author: Author of the configuration file. 1882 @param revision: Revision of the configuration file. 1883 @param description: Description of the configuration file. 1884 @param generator: Tool that generated the configuration file. 1885 """ 1886 self._author = None 1887 self._revision = None 1888 self._description = None 1889 self._generator = None 1890 self.author = author 1891 self.revision = revision 1892 self.description = description 1893 self.generator = generator
1894
1895 - def __repr__(self):
1896 """ 1897 Official string representation for class instance. 1898 """ 1899 return "ReferenceConfig(%s, %s, %s, %s)" % (self.author, self.revision, self.description, self.generator)
1900
1901 - def __str__(self):
1902 """ 1903 Informal string representation for class instance. 1904 """ 1905 return self.__repr__()
1906
1907 - def __cmp__(self, other):
1908 """ 1909 Definition of equals operator for this class. 1910 @param other: Other object to compare to. 1911 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 1912 """ 1913 if other is None: 1914 return 1 1915 if self._author != other._author: 1916 if self._author < other._author: 1917 return -1 1918 else: 1919 return 1 1920 if self._revision != other._revision: 1921 if self._revision < other._revision: 1922 return -1 1923 else: 1924 return 1 1925 if self._description != other._description: 1926 if self._description < other._description: 1927 return -1 1928 else: 1929 return 1 1930 if self._generator != other._generator: 1931 if self._generator < other._generator: 1932 return -1 1933 else: 1934 return 1 1935 return 0
1936
1937 - def _setAuthor(self, value):
1938 """ 1939 Property target used to set the author value. 1940 No validations. 1941 """ 1942 self._author = value
1943
1944 - def _getAuthor(self):
1945 """ 1946 Property target used to get the author value. 1947 """ 1948 return self._author
1949
1950 - def _setRevision(self, value):
1951 """ 1952 Property target used to set the revision value. 1953 No validations. 1954 """ 1955 self._revision = value
1956
1957 - def _getRevision(self):
1958 """ 1959 Property target used to get the revision value. 1960 """ 1961 return self._revision
1962
1963 - def _setDescription(self, value):
1964 """ 1965 Property target used to set the description value. 1966 No validations. 1967 """ 1968 self._description = value
1969
1970 - def _getDescription(self):
1971 """ 1972 Property target used to get the description value. 1973 """ 1974 return self._description
1975
1976 - def _setGenerator(self, value):
1977 """ 1978 Property target used to set the generator value. 1979 No validations. 1980 """ 1981 self._generator = value
1982
1983 - def _getGenerator(self):
1984 """ 1985 Property target used to get the generator value. 1986 """ 1987 return self._generator
1988 1989 author = property(_getAuthor, _setAuthor, None, "Author of the configuration file.") 1990 revision = property(_getRevision, _setRevision, None, "Revision of the configuration file.") 1991 description = property(_getDescription, _setDescription, None, "Description of the configuration file.") 1992 generator = property(_getGenerator, _setGenerator, None, "Tool that generated the configuration file.")
1993 1994 1995 ######################################################################## 1996 # ExtensionsConfig class definition 1997 ######################################################################## 1998
1999 -class ExtensionsConfig(object):
2000 2001 """ 2002 Class representing Cedar Backup extensions configuration. 2003 2004 Extensions configuration is used to specify "extended actions" implemented 2005 by code external to Cedar Backup. For instance, a hypothetical third party 2006 might write extension code to collect database repository data. If they 2007 write a properly-formatted extension function, they can use the extension 2008 configuration to map a command-line Cedar Backup action (i.e. "database") 2009 to their function. 2010 2011 As with all of the other classes that represent configuration sections, all 2012 of these values are optional. It is up to some higher-level construct to 2013 decide whether everything they need is filled in. Some validation is done 2014 on non-C{None} assignments through the use of the Python C{property()} 2015 construct. 2016 2017 The following restrictions exist on data in this class: 2018 2019 - If set, the order mode must be one of the values in C{VALID_ORDER_MODES} 2020 - The actions list must be a list of C{ExtendedAction} objects. 2021 2022 @sort: __init__, __repr__, __str__, __cmp__, orderMode, actions 2023 """ 2024
2025 - def __init__(self, actions=None, orderMode=None):
2026 """ 2027 Constructor for the C{ExtensionsConfig} class. 2028 @param actions: List of extended actions 2029 """ 2030 self._orderMode = None 2031 self._actions = None 2032 self.orderMode = orderMode 2033 self.actions = actions
2034
2035 - def __repr__(self):
2036 """ 2037 Official string representation for class instance. 2038 """ 2039 return "ExtensionsConfig(%s, %s)" % (self.orderMode, self.actions)
2040
2041 - def __str__(self):
2042 """ 2043 Informal string representation for class instance. 2044 """ 2045 return self.__repr__()
2046
2047 - def __cmp__(self, other):
2048 """ 2049 Definition of equals operator for this class. 2050 @param other: Other object to compare to. 2051 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 2052 """ 2053 if other is None: 2054 return 1 2055 if self._orderMode != other._orderMode: 2056 if self._orderMode < other._orderMode: 2057 return -1 2058 else: 2059 return 1 2060 if self._actions != other._actions: 2061 if self._actions < other._actions: 2062 return -1 2063 else: 2064 return 1 2065 return 0
2066
2067 - def _setOrderMode(self, value):
2068 """ 2069 Property target used to set the order mode. 2070 The value must be one of L{VALID_ORDER_MODES}. 2071 @raise ValueError: If the value is not valid. 2072 """ 2073 if value is not None: 2074 if value not in VALID_ORDER_MODES: 2075 raise ValueError("Order mode must be one of %s." % VALID_ORDER_MODES) 2076 self._orderMode = value
2077
2078 - def _getOrderMode(self):
2079 """ 2080 Property target used to get the order mode. 2081 """ 2082 return self._orderMode
2083
2084 - def _setActions(self, value):
2085 """ 2086 Property target used to set the actions list. 2087 Either the value must be C{None} or each element must be an C{ExtendedAction}. 2088 @raise ValueError: If the value is not a C{ExtendedAction} 2089 """ 2090 if value is None: 2091 self._actions = None 2092 else: 2093 try: 2094 saved = self._actions 2095 self._actions = ObjectTypeList(ExtendedAction, "ExtendedAction") 2096 self._actions.extend(value) 2097 except Exception, e: 2098 self._actions = saved 2099 raise e
2100
2101 - def _getActions(self):
2102 """ 2103 Property target used to get the actions list. 2104 """ 2105 return self._actions
2106 2107 orderMode = property(_getOrderMode, _setOrderMode, None, "Order mode for extensions, to control execution ordering.") 2108 actions = property(_getActions, _setActions, None, "List of extended actions.")
2109 2110 2111 ######################################################################## 2112 # OptionsConfig class definition 2113 ######################################################################## 2114
2115 -class OptionsConfig(object):
2116 2117 """ 2118 Class representing a Cedar Backup global options configuration. 2119 2120 The options section is used to store global configuration options and 2121 defaults that can be applied to other sections. 2122 2123 As with all of the other classes that represent configuration sections, all 2124 of these values are optional. It is up to some higher-level construct to 2125 decide whether everything they need is filled in. Some validation is done 2126 on non-C{None} assignments through the use of the Python C{property()} 2127 construct. 2128 2129 The following restrictions exist on data in this class: 2130 2131 - The working directory must be an absolute path. 2132 - The starting day must be a day of the week in English, i.e. C{"monday"}, C{"tuesday"}, etc. 2133 - All of the other values must be non-empty strings if they are set to something other than C{None}. 2134 - The overrides list must be a list of C{CommandOverride} objects. 2135 - The hooks list must be a list of C{ActionHook} objects. 2136 2137 @sort: __init__, __repr__, __str__, __cmp__, startingDay, workingDir, 2138 backupUser, backupGroup, rcpCommand, overrides 2139 """ 2140
2141 - def __init__(self, startingDay=None, workingDir=None, backupUser=None, 2142 backupGroup=None, rcpCommand=None, overrides=None, hooks=None):
2143 """ 2144 Constructor for the C{OptionsConfig} class. 2145 2146 @param startingDay: Day that starts the week. 2147 @param workingDir: Working (temporary) directory to use for backups. 2148 @param backupUser: Effective user that backups should run as. 2149 @param backupGroup: Effective group that backups should run as. 2150 @param rcpCommand: Default rcp-compatible copy command for staging. 2151 @param overrides: List of configured command path overrides, if any. 2152 @param hooks: List of configured pre- and post-action hooks. 2153 2154 @raise ValueError: If one of the values is invalid. 2155 """ 2156 self._startingDay = None 2157 self._workingDir = None 2158 self._backupUser = None 2159 self._backupGroup = None 2160 self._rcpCommand = None 2161 self._overrides = None 2162 self._hooks = None 2163 self.startingDay = startingDay 2164 self.workingDir = workingDir 2165 self.backupUser = backupUser 2166 self.backupGroup = backupGroup 2167 self.rcpCommand = rcpCommand 2168 self.overrides = overrides 2169 self.hooks = hooks
2170
2171 - def __repr__(self):
2172 """ 2173 Official string representation for class instance. 2174 """ 2175 return "OptionsConfig(%s, %s, %s, %s, %s, %s, %s)" % (self.startingDay, self.workingDir, 2176 self.backupUser, self.backupGroup, 2177 self.rcpCommand, self.overrides, 2178 self.hooks)
2179
2180 - def __str__(self):
2181 """ 2182 Informal string representation for class instance. 2183 """ 2184 return self.__repr__()
2185
2186 - def __cmp__(self, other):
2187 """ 2188 Definition of equals operator for this class. 2189 @param other: Other object to compare to. 2190 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 2191 """ 2192 if other is None: 2193 return 1 2194 if self._startingDay != other._startingDay: 2195 if self._startingDay < other._startingDay: 2196 return -1 2197 else: 2198 return 1 2199 if self._workingDir != other._workingDir: 2200 if self._workingDir < other._workingDir: 2201 return -1 2202 else: 2203 return 1 2204 if self._backupUser != other._backupUser: 2205 if self._backupUser < other._backupUser: 2206 return -1 2207 else: 2208 return 1 2209 if self._backupGroup != other._backupGroup: 2210 if self._backupGroup < other._backupGroup: 2211 return -1 2212 else: 2213 return 1 2214 if self._rcpCommand != other._rcpCommand: 2215 if self._rcpCommand < other._rcpCommand: 2216 return -1 2217 else: 2218 return 1 2219 if self._overrides != other._overrides: 2220 if self._overrides < other._overrides: 2221 return -1 2222 else: 2223 return 1 2224 if self._hooks != other._hooks: 2225 if self._hooks < other._hooks: 2226 return -1 2227 else: 2228 return 1 2229 return 0
2230
2231 - def _setStartingDay(self, value):
2232 """ 2233 Property target used to set the starting day. 2234 If it is not C{None}, the value must be a valid English day of the week, 2235 one of C{"monday"}, C{"tuesday"}, C{"wednesday"}, etc. 2236 @raise ValueError: If the value is not a valid day of the week. 2237 """ 2238 if value is not None: 2239 if value not in ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday", ]: 2240 raise ValueError("Starting day must be an English day of the week, i.e. \"monday\".") 2241 self._startingDay = value
2242
2243 - def _getStartingDay(self):
2244 """ 2245 Property target used to get the starting day. 2246 """ 2247 return self._startingDay
2248
2249 - def _setWorkingDir(self, value):
2250 """ 2251 Property target used to set the working directory. 2252 The value must be an absolute path if it is not C{None}. 2253 It does not have to exist on disk at the time of assignment. 2254 @raise ValueError: If the value is not an absolute path. 2255 @raise ValueError: If the value cannot be encoded properly. 2256 """ 2257 if value is not None: 2258 if not os.path.isabs(value): 2259 raise ValueError("Working directory must be an absolute path.") 2260 self._workingDir = encodePath(value)
2261
2262 - def _getWorkingDir(self):
2263 """ 2264 Property target used to get the working directory. 2265 """ 2266 return self._workingDir
2267
2268 - def _setBackupUser(self, value):
2269 """ 2270 Property target used to set the backup user. 2271 The value must be a non-empty string if it is not C{None}. 2272 @raise ValueError: If the value is an empty string. 2273 """ 2274 if value is not None: 2275 if len(value) < 1: 2276 raise ValueError("Backup user must be a non-empty string.") 2277 self._backupUser = value
2278
2279 - def _getBackupUser(self):
2280 """ 2281 Property target used to get the backup user. 2282 """ 2283 return self._backupUser
2284
2285 - def _setBackupGroup(self, value):
2286 """ 2287 Property target used to set the backup group. 2288 The value must be a non-empty string if it is not C{None}. 2289 @raise ValueError: If the value is an empty string. 2290 """ 2291 if value is not None: 2292 if len(value) < 1: 2293 raise ValueError("Backup group must be a non-empty string.") 2294 self._backupGroup = value
2295
2296 - def _getBackupGroup(self):
2297 """ 2298 Property target used to get the backup group. 2299 """ 2300 return self._backupGroup
2301
2302 - def _setRcpCommand(self, value):
2303 """ 2304 Property target used to set the rcp command. 2305 The value must be a non-empty string if it is not C{None}. 2306 @raise ValueError: If the value is an empty string. 2307 """ 2308 if value is not None: 2309 if len(value) < 1: 2310 raise ValueError("The rcp command must be a non-empty string.") 2311 self._rcpCommand = value
2312
2313 - def _getRcpCommand(self):
2314 """ 2315 Property target used to get the rcp command. 2316 """ 2317 return self._rcpCommand
2318
2319 - def _setOverrides(self, value):
2320 """ 2321 Property target used to set the command path overrides list. 2322 Either the value must be C{None} or each element must be a C{CommandOverride}. 2323 @raise ValueError: If the value is not a C{CommandOverride} 2324 """ 2325 if value is None: 2326 self._overrides = None 2327 else: 2328 try: 2329 saved = self._overrides 2330 self._overrides = ObjectTypeList(CommandOverride, "CommandOverride") 2331 self._overrides.extend(value) 2332 except Exception, e: 2333 self._overrides = saved 2334 raise e
2335
2336 - def _getOverrides(self):
2337 """ 2338 Property target used to get the command path overrides list. 2339 """ 2340 return self._overrides
2341
2342 - def _setHooks(self, value):
2343 """ 2344 Property target used to set the pre- and post-action hooks list. 2345 Either the value must be C{None} or each element must be an C{ActionHook}. 2346 @raise ValueError: If the value is not a C{CommandOverride} 2347 """ 2348 if value is None: 2349 self._hooks = None 2350 else: 2351 try: 2352 saved = self._hooks 2353 self._hooks = ObjectTypeList(ActionHook, "ActionHook") 2354 self._hooks.extend(value) 2355 except Exception, e: 2356 self._hooks = saved 2357 raise e
2358
2359 - def _getHooks(self):
2360 """ 2361 Property target used to get the command path hooks list. 2362 """ 2363 return self._hooks
2364 2365 startingDay = property(_getStartingDay, _setStartingDay, None, "Day that starts the week.") 2366 workingDir = property(_getWorkingDir, _setWorkingDir, None, "Working (temporary) directory to use for backups.") 2367 backupUser = property(_getBackupUser, _setBackupUser, None, "Effective user that backups should run as.") 2368 backupGroup = property(_getBackupGroup, _setBackupGroup, None, "Effective group that backups should run as.") 2369 rcpCommand = property(_getRcpCommand, _setRcpCommand, None, "Default rcp-compatible copy command for staging.") 2370 overrides = property(_getOverrides, _setOverrides, None, "List of configured command path overrides, if any.") 2371 hooks = property(_getHooks, _setHooks, None, "List of configured pre- and post-action hooks.")
2372 2373 2374 ######################################################################## 2375 # CollectConfig class definition 2376 ######################################################################## 2377
2378 -class CollectConfig(object):
2379 2380 """ 2381 Class representing a Cedar Backup collect configuration. 2382 2383 As with all of the other classes that represent configuration sections, all 2384 of these values are optional. It is up to some higher-level construct to 2385 decide whether everything they need is filled in. Some validation is done 2386 on non-C{None} assignments through the use of the Python C{property()} 2387 construct. 2388 2389 The following restrictions exist on data in this class: 2390 2391 - The target directory must be an absolute path. 2392 - The collect mode must be one of the values in L{VALID_COLLECT_MODES}. 2393 - The archive mode must be one of the values in L{VALID_ARCHIVE_MODES}. 2394 - The ignore file must be a non-empty string. 2395 - Each of the paths in C{absoluteExcludePaths} must be an absolute path 2396 - The collect file list must be a list of C{CollectFile} objects. 2397 - The collect directory list must be a list of C{CollectDir} objects. 2398 2399 For the C{absoluteExcludePaths} list, validation is accomplished through the 2400 L{util.AbsolutePathList} list implementation that overrides common list 2401 methods and transparently does the absolute path validation for us. 2402 2403 For the C{collectFiles} and C{collectDirs} list, validation is accomplished 2404 through the L{util.ObjectTypeList} list implementation that overrides common 2405 list methods and transparently ensures that each element has an appropriate 2406 type. 2407 2408 @note: Lists within this class are "unordered" for equality comparisons. 2409 2410 @sort: __init__, __repr__, __str__, __cmp__, targetDir, 2411 collectMode, archiveMode, ignoreFile, absoluteExcludePaths, 2412 excludePatterns, collectFiles, collectDirs 2413 """ 2414
2415 - def __init__(self, targetDir=None, collectMode=None, archiveMode=None, ignoreFile=None, 2416 absoluteExcludePaths=None, excludePatterns=None, collectFiles=None, collectDirs=None):
2417 """ 2418 Constructor for the C{CollectConfig} class. 2419 2420 @param targetDir: Directory to collect files into. 2421 @param collectMode: Default collect mode. 2422 @param archiveMode: Default archive mode for collect files. 2423 @param ignoreFile: Default ignore file name. 2424 @param absoluteExcludePaths: List of absolute paths to exclude. 2425 @param excludePatterns: List of regular expression patterns to exclude. 2426 @param collectFiles: List of collect files. 2427 @param collectDirs: List of collect directories. 2428 2429 @raise ValueError: If one of the values is invalid. 2430 """ 2431 self._targetDir = None 2432 self._collectMode = None 2433 self._archiveMode = None 2434 self._ignoreFile = None 2435 self._absoluteExcludePaths = None 2436 self._excludePatterns = None 2437 self._collectFiles = None 2438 self._collectDirs = None 2439 self.targetDir = targetDir 2440 self.collectMode = collectMode 2441 self.archiveMode = archiveMode 2442 self.ignoreFile = ignoreFile 2443 self.absoluteExcludePaths = absoluteExcludePaths 2444 self.excludePatterns = excludePatterns 2445 self.collectFiles = collectFiles 2446 self.collectDirs = collectDirs
2447
2448 - def __repr__(self):
2449 """ 2450 Official string representation for class instance. 2451 """ 2452 return "CollectConfig(%s, %s, %s, %s, %s, %s, %s, %s)" % (self.targetDir, self.collectMode, self.archiveMode, 2453 self.ignoreFile, self.absoluteExcludePaths, 2454 self.excludePatterns, self.collectFiles, self.collectDirs)
2455
2456 - def __str__(self):
2457 """ 2458 Informal string representation for class instance. 2459 """ 2460 return self.__repr__()
2461
2462 - def __cmp__(self, other):
2463 """ 2464 Definition of equals operator for this class. 2465 Lists within this class are "unordered" for equality comparisons. 2466 @param other: Other object to compare to. 2467 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 2468 """ 2469 if other is None: 2470 return 1 2471 if self._targetDir != other._targetDir: 2472 if self._targetDir < other._targetDir: 2473 return -1 2474 else: 2475 return 1 2476 if self._collectMode != other._collectMode: 2477 if self._collectMode < other._collectMode: 2478 return -1 2479 else: 2480 return 1 2481 if self._archiveMode != other._archiveMode: 2482 if self._archiveMode < other._archiveMode: 2483 return -1 2484 else: 2485 return 1 2486 if self._ignoreFile != other._ignoreFile: 2487 if self._ignoreFile < other._ignoreFile: 2488 return -1 2489 else: 2490 return 1 2491 if self._absoluteExcludePaths != other._absoluteExcludePaths: 2492 if self._absoluteExcludePaths < other._absoluteExcludePaths: 2493 return -1 2494 else: 2495 return 1 2496 if self._excludePatterns != other._excludePatterns: 2497 if self._excludePatterns < other._excludePatterns: 2498 return -1 2499 else: 2500 return 1 2501 if self._collectFiles != other._collectFiles: 2502 if self._collectFiles < other._collectFiles: 2503 return -1 2504 else: 2505 return 1 2506 if self._collectDirs != other._collectDirs: 2507 if self._collectDirs < other._collectDirs: 2508 return -1 2509 else: 2510 return 1 2511 return 0
2512
2513 - def _setTargetDir(self, value):
2514 """ 2515 Property target used to set the target directory. 2516 The value must be an absolute path if it is not C{None}. 2517 It does not have to exist on disk at the time of assignment. 2518 @raise ValueError: If the value is not an absolute path. 2519 @raise ValueError: If the value cannot be encoded properly. 2520 """ 2521 if value is not None: 2522 if not os.path.isabs(value): 2523 raise ValueError("Target directory must be an absolute path.") 2524 self._targetDir = encodePath(value)
2525
2526 - def _getTargetDir(self):
2527 """ 2528 Property target used to get the target directory. 2529 """ 2530 return self._targetDir
2531
2532 - def _setCollectMode(self, value):
2533 """ 2534 Property target used to set the collect mode. 2535 If not C{None}, the mode must be one of L{VALID_COLLECT_MODES}. 2536 @raise ValueError: If the value is not valid. 2537 """ 2538 if value is not None: 2539 if value not in VALID_COLLECT_MODES: 2540 raise ValueError("Collect mode must be one of %s." % VALID_COLLECT_MODES) 2541 self._collectMode = value
2542
2543 - def _getCollectMode(self):
2544 """ 2545 Property target used to get the collect mode. 2546 """ 2547 return self._collectMode
2548
2549 - def _setArchiveMode(self, value):
2550 """ 2551 Property target used to set the archive mode. 2552 If not C{None}, the mode must be one of L{VALID_ARCHIVE_MODES}. 2553 @raise ValueError: If the value is not valid. 2554 """ 2555 if value is not None: 2556 if value not in VALID_ARCHIVE_MODES: 2557 raise ValueError("Archive mode must be one of %s." % VALID_ARCHIVE_MODES) 2558 self._archiveMode = value
2559
2560 - def _getArchiveMode(self):
2561 """ 2562 Property target used to get the archive mode. 2563 """ 2564 return self._archiveMode
2565
2566 - def _setIgnoreFile(self, value):
2567 """ 2568 Property target used to set the ignore file. 2569 The value must be a non-empty string if it is not C{None}. 2570 @raise ValueError: If the value is an empty string. 2571 @raise ValueError: If the value cannot be encoded properly. 2572 """ 2573 if value is not None: 2574 if len(value) < 1: 2575 raise ValueError("The ignore file must be a non-empty string.") 2576 self._ignoreFile = encodePath(value)
2577
2578 - def _getIgnoreFile(self):
2579 """ 2580 Property target used to get the ignore file. 2581 """ 2582 return self._ignoreFile
2583
2584 - def _setAbsoluteExcludePaths(self, value):
2585 """ 2586 Property target used to set the absolute exclude paths list. 2587 Either the value must be C{None} or each element must be an absolute path. 2588 Elements do not have to exist on disk at the time of assignment. 2589 @raise ValueError: If the value is not an absolute path. 2590 """ 2591 if value is None: 2592 self._absoluteExcludePaths = None 2593 else: 2594 try: 2595 saved = self._absoluteExcludePaths 2596 self._absoluteExcludePaths = AbsolutePathList() 2597 self._absoluteExcludePaths.extend(value) 2598 except Exception, e: 2599 self._absoluteExcludePaths = saved 2600 raise e
2601
2602 - def _getAbsoluteExcludePaths(self):
2603 """ 2604 Property target used to get the absolute exclude paths list. 2605 """ 2606 return self._absoluteExcludePaths
2607
2608 - def _setExcludePatterns(self, value):
2609 """ 2610 Property target used to set the exclude patterns list. 2611 """ 2612 if value is None: 2613 self._excludePatterns = None 2614 else: 2615 try: 2616 saved = self._excludePatterns 2617 self._excludePatterns = RegexList() 2618 self._excludePatterns.extend(value) 2619 except Exception, e: 2620 self._excludePatterns = saved 2621 raise e
2622
2623 - def _getExcludePatterns(self):
2624 """ 2625 Property target used to get the exclude patterns list. 2626 """ 2627 return self._excludePatterns
2628
2629 - def _setCollectFiles(self, value):
2630 """ 2631 Property target used to set the collect files list. 2632 Either the value must be C{None} or each element must be a C{CollectFile}. 2633 @raise ValueError: If the value is not a C{CollectFile} 2634 """ 2635 if value is None: 2636 self._collectFiles = None 2637 else: 2638 try: 2639 saved = self._collectFiles 2640 self._collectFiles = ObjectTypeList(CollectFile, "CollectFile") 2641 self._collectFiles.extend(value) 2642 except Exception, e: 2643 self._collectFiles = saved 2644 raise e
2645
2646 - def _getCollectFiles(self):
2647 """ 2648 Property target used to get the collect files list. 2649 """ 2650 return self._collectFiles
2651
2652 - def _setCollectDirs(self, value):
2653 """ 2654 Property target used to set the collect dirs list. 2655 Either the value must be C{None} or each element must be a C{CollectDir}. 2656 @raise ValueError: If the value is not a C{CollectDir} 2657 """ 2658 if value is None: 2659 self._collectDirs = None 2660 else: 2661 try: 2662 saved = self._collectDirs 2663 self._collectDirs = ObjectTypeList(CollectDir, "CollectDir") 2664 self._collectDirs.extend(value) 2665 except Exception, e: 2666 self._collectDirs = saved 2667 raise e
2668
2669 - def _getCollectDirs(self):
2670 """ 2671 Property target used to get the collect dirs list. 2672 """ 2673 return self._collectDirs
2674 2675 targetDir = property(_getTargetDir, _setTargetDir, None, "Directory to collect files into.") 2676 collectMode = property(_getCollectMode, _setCollectMode, None, "Default collect mode.") 2677 archiveMode = property(_getArchiveMode, _setArchiveMode, None, "Default archive mode for collect files.") 2678 ignoreFile = property(_getIgnoreFile, _setIgnoreFile, None, "Default ignore file name.") 2679 absoluteExcludePaths = property(_getAbsoluteExcludePaths, _setAbsoluteExcludePaths, None, "List of absolute paths to exclude.") 2680 excludePatterns = property(_getExcludePatterns, _setExcludePatterns, None, "List of regular expressions patterns to exclude.") 2681 collectFiles = property(_getCollectFiles, _setCollectFiles, None, "List of collect files.") 2682 collectDirs = property(_getCollectDirs, _setCollectDirs, None, "List of collect directories.")
2683 2684 2685 ######################################################################## 2686 # StageConfig class definition 2687 ######################################################################## 2688
2689 -class StageConfig(object):
2690 2691 """ 2692 Class representing a Cedar Backup stage configuration. 2693 2694 As with all of the other classes that represent configuration sections, all 2695 of these values are optional. It is up to some higher-level construct to 2696 decide whether everything they need is filled in. Some validation is done 2697 on non-C{None} assignments through the use of the Python C{property()} 2698 construct. 2699 2700 The following restrictions exist on data in this class: 2701 2702 - The target directory must be an absolute path 2703 - The list of local peers must contain only C{LocalPeer} objects 2704 - The list of remote peers must contain only C{RemotePeer} objects 2705 2706 @note: Lists within this class are "unordered" for equality comparisons. 2707 2708 @sort: __init__, __repr__, __str__, __cmp__, targetDir, localPeers, remotePeers 2709 """ 2710
2711 - def __init__(self, targetDir=None, localPeers=None, remotePeers=None):
2712 """ 2713 Constructor for the C{StageConfig} class. 2714 2715 @param targetDir: Directory to stage files into, by peer name. 2716 @param localPeers: List of local peers. 2717 @param remotePeers: List of remote peers. 2718 2719 @raise ValueError: If one of the values is invalid. 2720 """ 2721 self._targetDir = None 2722 self._localPeers = None 2723 self._remotePeers = None 2724 self.targetDir = targetDir 2725 self.localPeers = localPeers 2726 self.remotePeers = remotePeers
2727
2728 - def __repr__(self):
2729 """ 2730 Official string representation for class instance. 2731 """ 2732 return "StageConfig(%s, %s, %s)" % (self.targetDir, self.localPeers, self.remotePeers)
2733
2734 - def __str__(self):
2735 """ 2736 Informal string representation for class instance. 2737 """ 2738 return self.__repr__()
2739
2740 - def __cmp__(self, other):
2741 """ 2742 Definition of equals operator for this class. 2743 Lists within this class are "unordered" for equality comparisons. 2744 @param other: Other object to compare to. 2745 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 2746 """ 2747 if other is None: 2748 return 1 2749 if self._targetDir != other._targetDir: 2750 if self._targetDir < other._targetDir: 2751 return -1 2752 else: 2753 return 1 2754 if self._localPeers != other._localPeers: 2755 if self._localPeers < other._localPeers: 2756 return -1 2757 else: 2758 return 1 2759 if self._remotePeers != other._remotePeers: 2760 if self._remotePeers < other._remotePeers: 2761 return -1 2762 else: 2763 return 1 2764 return 0
2765
2766 - def _setTargetDir(self, value):
2767 """ 2768 Property target used to set the target directory. 2769 The value must be an absolute path if it is not C{None}. 2770 It does not have to exist on disk at the time of assignment. 2771 @raise ValueError: If the value is not an absolute path. 2772 @raise ValueError: If the value cannot be encoded properly. 2773 """ 2774 if value is not None: 2775 if not os.path.isabs(value): 2776 raise ValueError("Target directory must be an absolute path.") 2777 self._targetDir = encodePath(value)
2778
2779 - def _getTargetDir(self):
2780 """ 2781 Property target used to get the target directory. 2782 """ 2783 return self._targetDir
2784
2785 - def _setLocalPeers(self, value):
2786 """ 2787 Property target used to set the local peers list. 2788 Either the value must be C{None} or each element must be a C{LocalPeer}. 2789 @raise ValueError: If the value is not an absolute path. 2790 """ 2791 if value is None: 2792 self._localPeers = None 2793 else: 2794 try: 2795 saved = self._localPeers 2796 self._localPeers = ObjectTypeList(LocalPeer, "LocalPeer") 2797 self._localPeers.extend(value) 2798 except Exception, e: 2799 self._localPeers = saved 2800 raise e
2801
2802 - def _getLocalPeers(self):
2803 """ 2804 Property target used to get the local peers list. 2805 """ 2806 return self._localPeers
2807
2808 - def _setRemotePeers(self, value):
2809 """ 2810 Property target used to set the remote peers list. 2811 Either the value must be C{None} or each element must be a C{RemotePeer}. 2812 @raise ValueError: If the value is not a C{RemotePeer} 2813 """ 2814 if value is None: 2815 self._remotePeers = None 2816 else: 2817 try: 2818 saved = self._remotePeers 2819 self._remotePeers = ObjectTypeList(RemotePeer, "RemotePeer") 2820 self._remotePeers.extend(value) 2821 except Exception, e: 2822 self._remotePeers = saved 2823 raise e
2824
2825 - def _getRemotePeers(self):
2826 """ 2827 Property target used to get the remote peers list. 2828 """ 2829 return self._remotePeers
2830 2831 targetDir = property(_getTargetDir, _setTargetDir, None, "Directory to stage files into, by peer name.") 2832 localPeers = property(_getLocalPeers, _setLocalPeers, None, "List of local peers.") 2833 remotePeers = property(_getRemotePeers, _setRemotePeers, None, "List of remote peers.")
2834 2835 2836 ######################################################################## 2837 # StoreConfig class definition 2838 ######################################################################## 2839
2840 -class StoreConfig(object):
2841 2842 """ 2843 Class representing a Cedar Backup store configuration. 2844 2845 As with all of the other classes that represent configuration sections, all 2846 of these values are optional. It is up to some higher-level construct to 2847 decide whether everything they need is filled in. Some validation is done 2848 on non-C{None} assignments through the use of the Python C{property()} 2849 construct. 2850 2851 The following restrictions exist on data in this class: 2852 2853 - The source directory must be an absolute path. 2854 - The media type must be one of the values in L{VALID_MEDIA_TYPES}. 2855 - The device type must be one of the values in L{VALID_DEVICE_TYPES}. 2856 - The device path must be an absolute path. 2857 - The SCSI id, if provided, must be in the form specified by L{validateScsiId}. 2858 - The drive speed must be an integer >= 1 2859 - The blanking behavior must be a C{BlankBehavior} object 2860 2861 Note that although the blanking factor must be a positive floating point 2862 number, it is stored as a string. This is done so that we can losslessly go 2863 back and forth between XML and object representations of configuration. 2864 2865 @sort: __init__, __repr__, __str__, __cmp__, sourceDir, 2866 mediaType, deviceType, devicePath, deviceScsiId, 2867 driveSpeed, checkData, checkMedia, warnMidnite, noEject, blankBehavior 2868 """ 2869
2870 - def __init__(self, sourceDir=None, mediaType=None, deviceType=None, 2871 devicePath=None, deviceScsiId=None, driveSpeed=None, 2872 checkData=False, warnMidnite=False, noEject=False, 2873 checkMedia=False, blankBehavior=None):
2874 """ 2875 Constructor for the C{StoreConfig} class. 2876 2877 @param sourceDir: Directory whose contents should be written to media. 2878 @param mediaType: Type of the media (see notes above). 2879 @param deviceType: Type of the device (optional, see notes above). 2880 @param devicePath: Filesystem device name for writer device, i.e. C{/dev/cdrw}. 2881 @param deviceScsiId: SCSI id for writer device, i.e. C{[<method>:]scsibus,target,lun}. 2882 @param driveSpeed: Speed of the drive, i.e. C{2} for 2x drive, etc. 2883 @param checkData: Whether resulting image should be validated. 2884 @param checkMedia: Whether media should be checked before being written to. 2885 @param warnMidnite: Whether to generate warnings for crossing midnite. 2886 @param noEject: Indicates that the writer device should not be ejected. 2887 @param blankBehavior: Controls optimized blanking behavior. 2888 2889 @raise ValueError: If one of the values is invalid. 2890 """ 2891 self._sourceDir = None 2892 self._mediaType = None 2893 self._deviceType = None 2894 self._devicePath = None 2895 self._deviceScsiId = None 2896 self._driveSpeed = None 2897 self._checkData = None 2898 self._checkMedia = None 2899 self._warnMidnite = None 2900 self._noEject = None 2901 self._blankBehavior = None 2902 self.sourceDir = sourceDir 2903 self.mediaType = mediaType 2904 self.deviceType = deviceType 2905 self.devicePath = devicePath 2906 self.deviceScsiId = deviceScsiId 2907 self.driveSpeed = driveSpeed 2908 self.checkData = checkData 2909 self.checkMedia = checkMedia 2910 self.warnMidnite = warnMidnite 2911 self.noEject = noEject 2912 self.blankBehavior = blankBehavior
2913
2914 - def __repr__(self):
2915 """ 2916 Official string representation for class instance. 2917 """ 2918 return "StoreConfig(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" % (self.sourceDir, self.mediaType, self.deviceType, 2919 self.devicePath, self.deviceScsiId, self.driveSpeed, 2920 self.checkData, self.warnMidnite, self.noEject, 2921 self.checkMedia, self.blankBehavior)
2922
2923 - def __str__(self):
2924 """ 2925 Informal string representation for class instance. 2926 """ 2927 return self.__repr__()
2928
2929 - def __cmp__(self, other):
2930 """ 2931 Definition of equals operator for this class. 2932 @param other: Other object to compare to. 2933 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 2934 """ 2935 if other is None: 2936 return 1 2937 if self._sourceDir != other._sourceDir: 2938 if self._sourceDir < other._sourceDir: 2939 return -1 2940 else: 2941 return 1 2942 if self._mediaType != other._mediaType: 2943 if self._mediaType < other._mediaType: 2944 return -1 2945 else: 2946 return 1 2947 if self._deviceType != other._deviceType: 2948 if self._deviceType < other._deviceType: 2949 return -1 2950 else: 2951 return 1 2952 if self._devicePath != other._devicePath: 2953 if self._devicePath < other._devicePath: 2954 return -1 2955 else: 2956 return 1 2957 if self._deviceScsiId != other._deviceScsiId: 2958 if self._deviceScsiId < other._deviceScsiId: 2959 return -1 2960 else: 2961 return 1 2962 if self._driveSpeed != other._driveSpeed: 2963 if self._driveSpeed < other._driveSpeed: 2964 return -1 2965 else: 2966 return 1 2967 if self._checkData != other._checkData: 2968 if self._checkData < other._checkData: 2969 return -1 2970 else: 2971 return 1 2972 if self._checkMedia != other._checkMedia: 2973 if self._checkMedia < other._checkMedia: 2974 return -1 2975 else: 2976 return 1 2977 if self._warnMidnite != other._warnMidnite: 2978 if self._warnMidnite < other._warnMidnite: 2979 return -1 2980 else: 2981 return 1 2982 if self._noEject != other._noEject: 2983 if self._noEject < other._noEject: 2984 return -1 2985 else: 2986 return 1 2987 if self._blankBehavior != other._blankBehavior: 2988 if self._blankBehavior < other._blankBehavior: 2989 return -1 2990 else: 2991 return 1 2992 return 0
2993
2994 - def _setSourceDir(self, value):
2995 """ 2996 Property target used to set the source directory. 2997 The value must be an absolute path if it is not C{None}. 2998 It does not have to exist on disk at the time of assignment. 2999 @raise ValueError: If the value is not an absolute path. 3000 @raise ValueError: If the value cannot be encoded properly. 3001 """ 3002 if value is not None: 3003 if not os.path.isabs(value): 3004 raise ValueError("Source directory must be an absolute path.") 3005 self._sourceDir = encodePath(value)
3006
3007 - def _getSourceDir(self):
3008 """ 3009 Property target used to get the source directory. 3010 """ 3011 return self._sourceDir
3012
3013 - def _setMediaType(self, value):
3014 """ 3015 Property target used to set the media type. 3016 The value must be one of L{VALID_MEDIA_TYPES}. 3017 @raise ValueError: If the value is not valid. 3018 """ 3019 if value is not None: 3020 if value not in VALID_MEDIA_TYPES: 3021 raise ValueError("Media type must be one of %s." % VALID_MEDIA_TYPES) 3022 self._mediaType = value
3023
3024 - def _getMediaType(self):
3025 """ 3026 Property target used to get the media type. 3027 """ 3028 return self._mediaType
3029
3030 - def _setDeviceType(self, value):
3031 """ 3032 Property target used to set the device type. 3033 The value must be one of L{VALID_DEVICE_TYPES}. 3034 @raise ValueError: If the value is not valid. 3035 """ 3036 if value is not None: 3037 if value not in VALID_DEVICE_TYPES: 3038 raise ValueError("Device type must be one of %s." % VALID_DEVICE_TYPES) 3039 self._deviceType = value
3040
3041 - def _getDeviceType(self):
3042 """ 3043 Property target used to get the device type. 3044 """ 3045 return self._deviceType
3046
3047 - def _setDevicePath(self, value):
3048 """ 3049 Property target used to set the device path. 3050 The value must be an absolute path if it is not C{None}. 3051 It does not have to exist on disk at the time of assignment. 3052 @raise ValueError: If the value is not an absolute path. 3053 @raise ValueError: If the value cannot be encoded properly. 3054 """ 3055 if value is not None: 3056 if not os.path.isabs(value): 3057 raise ValueError("Device path must be an absolute path.") 3058 self._devicePath = encodePath(value)
3059
3060 - def _getDevicePath(self):
3061 """ 3062 Property target used to get the device path. 3063 """ 3064 return self._devicePath
3065
3066 - def _setDeviceScsiId(self, value):
3067 """ 3068 Property target used to set the SCSI id 3069 The SCSI id must be valid per L{validateScsiId}. 3070 @raise ValueError: If the value is not valid. 3071 """ 3072 if value is None: 3073 self._deviceScsiId = None 3074 else: 3075 self._deviceScsiId = validateScsiId(value)
3076
3077 - def _getDeviceScsiId(self):
3078 """ 3079 Property target used to get the SCSI id. 3080 """ 3081 return self._deviceScsiId
3082
3083 - def _setDriveSpeed(self, value):
3084 """ 3085 Property target used to set the drive speed. 3086 The drive speed must be valid per L{validateDriveSpeed}. 3087 @raise ValueError: If the value is not valid. 3088 """ 3089 self._driveSpeed = validateDriveSpeed(value)
3090
3091 - def _getDriveSpeed(self):
3092 """ 3093 Property target used to get the drive speed. 3094 """ 3095 return self._driveSpeed
3096
3097 - def _setCheckData(self, value):
3098 """ 3099 Property target used to set the check data flag. 3100 No validations, but we normalize the value to C{True} or C{False}. 3101 """ 3102 if value: 3103 self._checkData = True 3104 else: 3105 self._checkData = False
3106
3107 - def _getCheckData(self):
3108 """ 3109 Property target used to get the check data flag. 3110 """ 3111 return self._checkData
3112
3113 - def _setCheckMedia(self, value):
3114 """ 3115 Property target used to set the check media flag. 3116 No validations, but we normalize the value to C{True} or C{False}. 3117 """ 3118 if value: 3119 self._checkMedia = True 3120 else: 3121 self._checkMedia = False
3122
3123 - def _getCheckMedia(self):
3124 """ 3125 Property target used to get the check media flag. 3126 """ 3127 return self._checkMedia
3128
3129 - def _setWarnMidnite(self, value):
3130 """ 3131 Property target used to set the midnite warning flag. 3132 No validations, but we normalize the value to C{True} or C{False}. 3133 """ 3134 if value: 3135 self._warnMidnite = True 3136 else: 3137 self._warnMidnite = False
3138
3139 - def _getWarnMidnite(self):
3140 """ 3141 Property target used to get the midnite warning flag. 3142 """ 3143 return self._warnMidnite
3144
3145 - def _setNoEject(self, value):
3146 """ 3147 Property target used to set the no-eject flag. 3148 No validations, but we normalize the value to C{True} or C{False}. 3149 """ 3150 if value: 3151 self._noEject = True 3152 else: 3153 self._noEject = False
3154
3155 - def _getNoEject(self):
3156 """ 3157 Property target used to get the no-eject flag. 3158 """ 3159 return self._noEject
3160
3161 - def _setBlankBehavior(self, value):
3162 """ 3163 Property target used to set blanking behavior configuration. 3164 If not C{None}, the value must be a C{BlankBehavior} object. 3165 @raise ValueError: If the value is not a C{BlankBehavior} 3166 """ 3167 if value is None: 3168 self._blankBehavior = None 3169 else: 3170 if not isinstance(value, BlankBehavior): 3171 raise ValueError("Value must be a C{BlankBehavior} object.") 3172 self._blankBehavior = value
3173
3174 - def _getBlankBehavior(self):
3175 """ 3176 Property target used to get the blanking behavior configuration. 3177 """ 3178 return self._blankBehavior
3179 3180 sourceDir = property(_getSourceDir, _setSourceDir, None, "Directory whose contents should be written to media.") 3181 mediaType = property(_getMediaType, _setMediaType, None, "Type of the media (see notes above).") 3182 deviceType = property(_getDeviceType, _setDeviceType, None, "Type of the device (optional, see notes above).") 3183 devicePath = property(_getDevicePath, _setDevicePath, None, "Filesystem device name for writer device.") 3184 deviceScsiId = property(_getDeviceScsiId, _setDeviceScsiId, None, "SCSI id for writer device (optional, see notes above).") 3185 driveSpeed = property(_getDriveSpeed, _setDriveSpeed, None, "Speed of the drive.") 3186 checkData = property(_getCheckData, _setCheckData, None, "Whether resulting image should be validated.") 3187 checkMedia = property(_getCheckMedia, _setCheckMedia, None, "Whether media should be checked before being written to.") 3188 warnMidnite = property(_getWarnMidnite, _setWarnMidnite, None, "Whether to generate warnings for crossing midnite.") 3189 noEject = property(_getNoEject, _setNoEject, None, "Indicates that the writer device should not be ejected.") 3190 blankBehavior = property(_getBlankBehavior, _setBlankBehavior, None, "Controls optimized blanking behavior.")
3191 3192 3193 ######################################################################## 3194 # PurgeConfig class definition 3195 ######################################################################## 3196
3197 -class PurgeConfig(object):
3198 3199 """ 3200 Class representing a Cedar Backup purge configuration. 3201 3202 As with all of the other classes that represent configuration sections, all 3203 of these values are optional. It is up to some higher-level construct to 3204 decide whether everything they need is filled in. Some validation is done 3205 on non-C{None} assignments through the use of the Python C{property()} 3206 construct. 3207 3208 The following restrictions exist on data in this class: 3209 3210 - The purge directory list must be a list of C{PurgeDir} objects. 3211 3212 For the C{purgeDirs} list, validation is accomplished through the 3213 L{util.ObjectTypeList} list implementation that overrides common list 3214 methods and transparently ensures that each element is a C{PurgeDir}. 3215 3216 @note: Lists within this class are "unordered" for equality comparisons. 3217 3218 @sort: __init__, __repr__, __str__, __cmp__, purgeDirs 3219 """ 3220
3221 - def __init__(self, purgeDirs=None):
3222 """ 3223 Constructor for the C{Purge} class. 3224 @param purgeDirs: List of purge directories. 3225 @raise ValueError: If one of the values is invalid. 3226 """ 3227 self._purgeDirs = None 3228 self.purgeDirs = purgeDirs
3229
3230 - def __repr__(self):
3231 """ 3232 Official string representation for class instance. 3233 """ 3234 return "PurgeConfig(%s)" % self.purgeDirs
3235
3236 - def __str__(self):
3237 """ 3238 Informal string representation for class instance. 3239 """ 3240 return self.__repr__()
3241
3242 - def __cmp__(self, other):
3243 """ 3244 Definition of equals operator for this class. 3245 Lists within this class are "unordered" for equality comparisons. 3246 @param other: Other object to compare to. 3247 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 3248 """ 3249 if other is None: 3250 return 1 3251 if self._purgeDirs != other._purgeDirs: 3252 if self._purgeDirs < other._purgeDirs: 3253 return -1 3254 else: 3255 return 1 3256 return 0
3257
3258 - def _setPurgeDirs(self, value):
3259 """ 3260 Property target used to set the purge dirs list. 3261 Either the value must be C{None} or each element must be a C{PurgeDir}. 3262 @raise ValueError: If the value is not a C{PurgeDir} 3263 """ 3264 if value is None: 3265 self._purgeDirs = None 3266 else: 3267 try: 3268 saved = self._purgeDirs 3269 self._purgeDirs = ObjectTypeList(PurgeDir, "PurgeDir") 3270 self._purgeDirs.extend(value) 3271 except Exception, e: 3272 self._purgeDirs = saved 3273 raise e
3274
3275 - def _getPurgeDirs(self):
3276 """ 3277 Property target used to get the purge dirs list. 3278 """ 3279 return self._purgeDirs
3280 3281 purgeDirs = property(_getPurgeDirs, _setPurgeDirs, None, "List of directories to purge.")
3282 3283 3284 ######################################################################## 3285 # Config class definition 3286 ######################################################################## 3287
3288 -class Config(object):
3289 3290 ###################### 3291 # Class documentation 3292 ###################### 3293 3294 """ 3295 Class representing a Cedar Backup XML configuration document. 3296 3297 The C{Config} class is a Python object representation of a Cedar Backup XML 3298 configuration file. It is intended to be the only Python-language interface 3299 to Cedar Backup configuration on disk for both Cedar Backup itself and for 3300 external applications. 3301 3302 The object representation is two-way: XML data can be used to create a 3303 C{Config} object, and then changes to the object can be propogated back to 3304 disk. A C{Config} object can even be used to create a configuration file 3305 from scratch programmatically. 3306 3307 This class and the classes it is composed from often use Python's 3308 C{property} construct to validate input and limit access to values. Some 3309 validations can only be done once a document is considered "complete" 3310 (see module notes for more details). 3311 3312 Assignments to the various instance variables must match the expected 3313 type, i.e. C{reference} must be a C{ReferenceConfig}. The internal check 3314 uses the built-in C{isinstance} function, so it should be OK to use 3315 subclasses if you want to. 3316 3317 If an instance variable is not set, its value will be C{None}. When an 3318 object is initialized without using an XML document, all of the values 3319 will be C{None}. Even when an object is initialized using XML, some of 3320 the values might be C{None} because not every section is required. 3321 3322 @note: Lists within this class are "unordered" for equality comparisons. 3323 3324 @sort: __init__, __repr__, __str__, __cmp__, extractXml, validate, 3325 reference, extensions, options, collect, stage, store, purge, 3326 _getReference, _setReference, _getExtensions, _setExtensions, 3327 _getOptions, _setOptions, _getCollect, _setCollect, _getStage, 3328 _setStage, _getStore, _setStore, _getPurge, _setPurge 3329 """ 3330 3331 ############## 3332 # Constructor 3333 ############## 3334
3335 - def __init__(self, xmlData=None, xmlPath=None, validate=True):
3336 """ 3337 Initializes a configuration object. 3338 3339 If you initialize the object without passing either C{xmlData} or 3340 C{xmlPath}, then configuration will be empty and will be invalid until it 3341 is filled in properly. 3342 3343 No reference to the original XML data or original path is saved off by 3344 this class. Once the data has been parsed (successfully or not) this 3345 original information is discarded. 3346 3347 Unless the C{validate} argument is C{False}, the L{Config.validate} 3348 method will be called (with its default arguments) against configuration 3349 after successfully parsing any passed-in XML. Keep in mind that even if 3350 C{validate} is C{False}, it might not be possible to parse the passed-in 3351 XML document if lower-level validations fail. 3352 3353 @note: It is strongly suggested that the C{validate} option always be set 3354 to C{True} (the default) unless there is a specific need to read in 3355 invalid configuration from disk. 3356 3357 @param xmlData: XML data representing configuration. 3358 @type xmlData: String data. 3359 3360 @param xmlPath: Path to an XML file on disk. 3361 @type xmlPath: Absolute path to a file on disk. 3362 3363 @param validate: Validate the document after parsing it. 3364 @type validate: Boolean true/false. 3365 3366 @raise ValueError: If both C{xmlData} and C{xmlPath} are passed-in. 3367 @raise ValueError: If the XML data in C{xmlData} or C{xmlPath} cannot be parsed. 3368 @raise ValueError: If the parsed configuration document is not valid. 3369 """ 3370 self._reference = None 3371 self._extensions = None 3372 self._options = None 3373 self._collect = None 3374 self._stage = None 3375 self._store = None 3376 self._purge = None 3377 self.reference = None 3378 self.extensions = None 3379 self.options = None 3380 self.collect = None 3381 self.stage = None 3382 self.store = None 3383 self.purge = None 3384 if xmlData is not None and xmlPath is not None: 3385 raise ValueError("Use either xmlData or xmlPath, but not both.") 3386 if xmlData is not None: 3387 self._parseXmlData(xmlData) 3388 if validate: 3389 self.validate() 3390 elif xmlPath is not None: 3391 xmlData = open(xmlPath).read() 3392 self._parseXmlData(xmlData) 3393 if validate: 3394 self.validate()
3395 3396 3397 ######################### 3398 # String representations 3399 ######################### 3400
3401 - def __repr__(self):
3402 """ 3403 Official string representation for class instance. 3404 """ 3405 return "Config(%s, %s, %s, %s, %s, %s, %s)" % (self.reference, self.extensions, self.options, 3406 self.collect, self.stage, self.store, self.purge)
3407
3408 - def __str__(self):
3409 """ 3410 Informal string representation for class instance. 3411 """ 3412 return self.__repr__()
3413 3414 3415 ############################# 3416 # Standard comparison method 3417 ############################# 3418
3419 - def __cmp__(self, other):
3420 """ 3421 Definition of equals operator for this class. 3422 Lists within this class are "unordered" for equality comparisons. 3423 @param other: Other object to compare to. 3424 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 3425 """ 3426 if other is None: 3427 return 1 3428 if self._reference != other._reference: 3429 if self._reference < other._reference: 3430 return -1 3431 else: 3432 return 1 3433 if self._extensions != other._extensions: 3434 if self._extensions < other._extensions: 3435 return -1 3436 else: 3437 return 1 3438 if self._options != other._options: 3439 if self._options < other._options: 3440 return -1 3441 else: 3442 return 1 3443 if self._collect != other._collect: 3444 if self._collect < other._collect: 3445 return -1 3446 else: 3447 return 1 3448 if self._stage != other._stage: 3449 if self._stage < other._stage: 3450 return -1 3451 else: 3452 return 1 3453 if self._store != other._store: 3454 if self._store < other._store: 3455 return -1 3456 else: 3457 return 1 3458 if self._purge != other._purge: 3459 if self._purge < other._purge: 3460 return -1 3461 else: 3462 return 1 3463 return 0
3464 3465 3466 ############# 3467 # Properties 3468 ############# 3469
3470 - def _setReference(self, value):
3471 """ 3472 Property target used to set the reference configuration value. 3473 If not C{None}, the value must be a C{ReferenceConfig} object. 3474 @raise ValueError: If the value is not a C{ReferenceConfig} 3475 """ 3476 if value is None: 3477 self._reference = None 3478 else: 3479 if not isinstance(value, ReferenceConfig): 3480 raise ValueError("Value must be a C{ReferenceConfig} object.") 3481 self._reference = value
3482
3483 - def _getReference(self):
3484 """ 3485 Property target used to get the reference configuration value. 3486 """ 3487 return self._reference
3488
3489 - def _setExtensions(self, value):
3490 """ 3491 Property target used to set the extensions configuration value. 3492 If not C{None}, the value must be a C{ExtensionsConfig} object. 3493 @raise ValueError: If the value is not a C{ExtensionsConfig} 3494 """ 3495 if value is None: 3496 self._extensions = None 3497 else: 3498 if not isinstance(value, ExtensionsConfig): 3499 raise ValueError("Value must be a C{ExtensionsConfig} object.") 3500 self._extensions = value
3501
3502 - def _getExtensions(self):
3503 """ 3504 Property target used to get the extensions configuration value. 3505 """ 3506 return self._extensions
3507
3508 - def _setOptions(self, value):
3509 """ 3510 Property target used to set the options configuration value. 3511 If not C{None}, the value must be an C{OptionsConfig} object. 3512 @raise ValueError: If the value is not a C{OptionsConfig} 3513 """ 3514 if value is None: 3515 self._options = None 3516 else: 3517 if not isinstance(value, OptionsConfig): 3518 raise ValueError("Value must be a C{OptionsConfig} object.") 3519 self._options = value
3520
3521 - def _getOptions(self):
3522 """ 3523 Property target used to get the options configuration value. 3524 """ 3525 return self._options
3526
3527 - def _setCollect(self, value):
3528 """ 3529 Property target used to set the collect configuration value. 3530 If not C{None}, the value must be a C{CollectConfig} object. 3531 @raise ValueError: If the value is not a C{CollectConfig} 3532 """ 3533 if value is None: 3534 self._collect = None 3535 else: 3536 if not isinstance(value, CollectConfig): 3537 raise ValueError("Value must be a C{CollectConfig} object.") 3538 self._collect = value
3539
3540 - def _getCollect(self):
3541 """ 3542 Property target used to get the collect configuration value. 3543 """ 3544 return self._collect
3545
3546 - def _setStage(self, value):
3547 """ 3548 Property target used to set the stage configuration value. 3549 If not C{None}, the value must be a C{StageConfig} object. 3550 @raise ValueError: If the value is not a C{StageConfig} 3551 """ 3552 if value is None: 3553 self._stage = None 3554 else: 3555 if not isinstance(value, StageConfig): 3556 raise ValueError("Value must be a C{StageConfig} object.") 3557 self._stage = value
3558
3559 - def _getStage(self):
3560 """ 3561 Property target used to get the stage configuration value. 3562 """ 3563 return self._stage
3564
3565 - def _setStore(self, value):
3566 """ 3567 Property target used to set the store configuration value. 3568 If not C{None}, the value must be a C{StoreConfig} object. 3569 @raise ValueError: If the value is not a C{StoreConfig} 3570 """ 3571 if value is None: 3572 self._store = None 3573 else: 3574 if not isinstance(value, StoreConfig): 3575 raise ValueError("Value must be a C{StoreConfig} object.") 3576 self._store = value
3577
3578 - def _getStore(self):
3579 """ 3580 Property target used to get the store configuration value. 3581 """ 3582 return self._store
3583
3584 - def _setPurge(self, value):
3585 """ 3586 Property target used to set the purge configuration value. 3587 If not C{None}, the value must be a C{PurgeConfig} object. 3588 @raise ValueError: If the value is not a C{PurgeConfig} 3589 """ 3590 if value is None: 3591 self._purge = None 3592 else: 3593 if not isinstance(value, PurgeConfig): 3594 raise ValueError("Value must be a C{PurgeConfig} object.") 3595 self._purge = value
3596
3597 - def _getPurge(self):
3598 """ 3599 Property target used to get the purge configuration value. 3600 """ 3601 return self._purge
3602 3603 reference = property(_getReference, _setReference, None, "Reference configuration in terms of a C{ReferenceConfig} object.") 3604 extensions = property(_getExtensions, _setExtensions, None, "Extensions configuration in terms of a C{ExtensionsConfig} object.") 3605 options = property(_getOptions, _setOptions, None, "Options configuration in terms of a C{OptionsConfig} object.") 3606 collect = property(_getCollect, _setCollect, None, "Collect configuration in terms of a C{CollectConfig} object.") 3607 stage = property(_getStage, _setStage, None, "Stage configuration in terms of a C{StageConfig} object.") 3608 store = property(_getStore, _setStore, None, "Store configuration in terms of a C{StoreConfig} object.") 3609 purge = property(_getPurge, _setPurge, None, "Purge configuration in terms of a C{PurgeConfig} object.") 3610 3611 3612 ################# 3613 # Public methods 3614 ################# 3615
3616 - def extractXml(self, xmlPath=None, validate=True):
3617 """ 3618 Extracts configuration into an XML document. 3619 3620 If C{xmlPath} is not provided, then the XML document will be returned as 3621 a string. If C{xmlPath} is provided, then the XML document will be written 3622 to the file and C{None} will be returned. 3623 3624 Unless the C{validate} parameter is C{False}, the L{Config.validate} 3625 method will be called (with its default arguments) against the 3626 configuration before extracting the XML. If configuration is not valid, 3627 then an XML document will not be extracted. 3628 3629 @note: It is strongly suggested that the C{validate} option always be set 3630 to C{True} (the default) unless there is a specific need to write an 3631 invalid configuration file to disk. 3632 3633 @param xmlPath: Path to an XML file to create on disk. 3634 @type xmlPath: Absolute path to a file. 3635 3636 @param validate: Validate the document before extracting it. 3637 @type validate: Boolean true/false. 3638 3639 @return: XML string data or C{None} as described above. 3640 3641 @raise ValueError: If configuration within the object is not valid. 3642 @raise IOError: If there is an error writing to the file. 3643 @raise OSError: If there is an error writing to the file. 3644 """ 3645 if validate: 3646 self.validate() 3647 xmlData = self._extractXml() 3648 if xmlPath is not None: 3649 open(xmlPath, "w").write(xmlData) 3650 return None 3651 else: 3652 return xmlData
3653
3654 - def validate(self, requireOneAction=True, requireReference=False, requireExtensions=False, requireOptions=True, 3655 requireCollect=False, requireStage=False, requireStore=False, requirePurge=False):
3656 """ 3657 Validates configuration represented by the object. 3658 3659 This method encapsulates all of the validations that should apply to a 3660 fully "complete" document but are not already taken care of by earlier 3661 validations. It also provides some extra convenience functionality which 3662 might be useful to some people. The process of validation is laid out in 3663 the I{Validation} section in the class notes (above). 3664 3665 @param requireOneAction: Require at least one of the collect, stage, store or purge sections. 3666 @param requireReference: Require the reference section. 3667 @param requireExtensions: Require the extensions section. 3668 @param requireOptions: Require the options section. 3669 @param requireCollect: Require the collect section. 3670 @param requireStage: Require the stage section. 3671 @param requireStore: Require the store section. 3672 @param requirePurge: Require the purge section. 3673 3674 @raise ValueError: If one of the validations fails. 3675 """ 3676 if requireOneAction and (self.collect, self.stage, self.store, self.purge) == (None, None, None, None): 3677 raise ValueError("At least one of the collect, stage, store and purge sections is required.") 3678 if requireReference and self.reference is None: 3679 raise ValueError("The reference is section is required.") 3680 if requireExtensions and self.extensions is None: 3681 raise ValueError("The extensions is section is required.") 3682 if requireOptions and self.options is None: 3683 raise ValueError("The options is section is required.") 3684 if requireCollect and self.collect is None: 3685 raise ValueError("The collect is section is required.") 3686 if requireStage and self.stage is None: 3687 raise ValueError("The stage is section is required.") 3688 if requireStore and self.store is None: 3689 raise ValueError("The store is section is required.") 3690 if requirePurge and self.purge is None: 3691 raise ValueError("The purge is section is required.") 3692 self._validateContents()
3693 3694 3695 ##################################### 3696 # High-level methods for parsing XML 3697 ##################################### 3698
3699 - def _parseXmlData(self, xmlData):
3700 """ 3701 Internal method to parse an XML string into the object. 3702 3703 This method parses the XML document into a DOM tree (C{xmlDom}) and then 3704 calls individual static methods to parse each of the individual 3705 configuration sections. 3706 3707 Most of the validation we do here has to do with whether the document can 3708 be parsed and whether any values which exist are valid. We don't do much 3709 validation as to whether required elements actually exist unless we have 3710 to to make sense of the document (instead, that's the job of the 3711 L{validate} method). 3712 3713 @param xmlData: XML data to be parsed 3714 @type xmlData: String data 3715 3716 @raise ValueError: If the XML cannot be successfully parsed. 3717 """ 3718 (xmlDom, parentNode) = createInputDom(xmlData) 3719 self._reference = Config._parseReference(parentNode) 3720 self._extensions = Config._parseExtensions(parentNode) 3721 self._options = Config._parseOptions(parentNode) 3722 self._collect = Config._parseCollect(parentNode) 3723 self._stage = Config._parseStage(parentNode) 3724 self._store = Config._parseStore(parentNode) 3725 self._purge = Config._parsePurge(parentNode)
3726
3727 - def _parseReference(parentNode):
3728 """ 3729 Parses a reference configuration section. 3730 3731 We read the following fields:: 3732 3733 author //cb_config/reference/author 3734 revision //cb_config/reference/revision 3735 description //cb_config/reference/description 3736 generator //cb_config/reference/generator 3737 3738 @param parentNode: Parent node to search beneath. 3739 3740 @return: C{ReferenceConfig} object or C{None} if the section does not exist. 3741 @raise ValueError: If some filled-in value is invalid. 3742 """ 3743 reference = None 3744 sectionNode = readFirstChild(parentNode, "reference") 3745 if sectionNode is not None: 3746 reference = ReferenceConfig() 3747 reference.author = readString(sectionNode, "author") 3748 reference.revision = readString(sectionNode, "revision") 3749 reference.description = readString(sectionNode, "description") 3750 reference.generator = readString(sectionNode, "generator") 3751 return reference
3752 _parseReference = staticmethod(_parseReference) 3753
3754 - def _parseExtensions(parentNode):
3755 """ 3756 Parses an extensions configuration section. 3757 3758 We read the following fields:: 3759 3760 orderMode //cb_config/extensions/order_mode 3761 3762 We also read groups of the following items, one list element per item:: 3763 3764 name //cb_config/extensions/action/name 3765 module //cb_config/extensions/action/module 3766 function //cb_config/extensions/action/function 3767 index //cb_config/extensions/action/index 3768 dependencies //cb_config/extensions/action/depends 3769 3770 The extended actions are parsed by L{_parseExtendedActions}. 3771 3772 @param parentNode: Parent node to search beneath. 3773 3774 @return: C{ExtensionsConfig} object or C{None} if the section does not exist. 3775 @raise ValueError: If some filled-in value is invalid. 3776 """ 3777 extensions = None 3778 sectionNode = readFirstChild(parentNode, "extensions") 3779 if sectionNode is not None: 3780 extensions = ExtensionsConfig() 3781 extensions.orderMode = readString(sectionNode, "order_mode") 3782 extensions.actions = Config._parseExtendedActions(sectionNode) 3783 return extensions
3784 _parseExtensions = staticmethod(_parseExtensions) 3785
3786 - def _parseOptions(parentNode):
3787 """ 3788 Parses a options configuration section. 3789 3790 We read the following fields:: 3791 3792 startingDay //cb_config/options/starting_day 3793 workingDir //cb_config/options/working_dir 3794 backupUser //cb_config/options/backup_user 3795 backupGroup //cb_config/options/backup_group 3796 rcpCommand //cb_config/options/rcp_command 3797 3798 We also read groups of the following items, one list element per 3799 item:: 3800 3801 overrides //cb_config/options/override 3802 3803 The overrides are parsed by L{_parseOverrides}. 3804 3805 @param parentNode: Parent node to search beneath. 3806 3807 @return: C{OptionsConfig} object or C{None} if the section does not exist. 3808 @raise ValueError: If some filled-in value is invalid. 3809 """ 3810 options = None 3811 sectionNode = readFirstChild(parentNode, "options") 3812 if sectionNode is not None: 3813 options = OptionsConfig() 3814 options.startingDay = readString(sectionNode, "starting_day") 3815 options.workingDir = readString(sectionNode, "working_dir") 3816 options.backupUser = readString(sectionNode, "backup_user") 3817 options.backupGroup = readString(sectionNode, "backup_group") 3818 options.rcpCommand = readString(sectionNode, "rcp_command") 3819 options.overrides = Config._parseOverrides(sectionNode) 3820 options.hooks = Config._parseHooks(sectionNode) 3821 return options
3822 _parseOptions = staticmethod(_parseOptions) 3823
3824 - def _parseCollect(parentNode):
3825 """ 3826 Parses a collect configuration section. 3827 3828 We read the following individual fields:: 3829 3830 targetDir //cb_config/collect/collect_dir 3831 collectMode //cb_config/collect/collect_mode 3832 archiveMode //cb_config/collect/archive_mode 3833 ignoreFile //cb_config/collect/ignore_file 3834 3835 We also read groups of the following items, one list element per 3836 item:: 3837 3838 absoluteExcludePaths //cb_config/collect/exclude/abs_path 3839 excludePatterns //cb_config/collect/exclude/pattern 3840 collectFiles //cb_config/collect/file 3841 collectDirs //cb_config/collect/dir 3842 3843 The exclusions are parsed by L{_parseExclusions}, the collect files are 3844 parsed by L{_parseCollectFiles}, and the directories are parsed by 3845 L{_parseCollectDirs}. 3846 3847 @param parentNode: Parent node to search beneath. 3848 3849 @return: C{CollectConfig} object or C{None} if the section does not exist. 3850 @raise ValueError: If some filled-in value is invalid. 3851 """ 3852 collect = None 3853 sectionNode = readFirstChild(parentNode, "collect") 3854 if sectionNode is not None: 3855 collect = CollectConfig() 3856 collect.targetDir = readString(sectionNode, "collect_dir") 3857 collect.collectMode = readString(sectionNode, "collect_mode") 3858 collect.archiveMode = readString(sectionNode, "archive_mode") 3859 collect.ignoreFile = readString(sectionNode, "ignore_file") 3860 (collect.absoluteExcludePaths, unused, collect.excludePatterns) = Config._parseExclusions(sectionNode) 3861 collect.collectFiles = Config._parseCollectFiles(sectionNode) 3862 collect.collectDirs = Config._parseCollectDirs(sectionNode) 3863 return collect
3864 _parseCollect = staticmethod(_parseCollect) 3865
3866 - def _parseStage(parentNode):
3867 """ 3868 Parses a stage configuration section. 3869 3870 We read the following individual fields:: 3871 3872 targetDir //cb_config/stage/staging_dir 3873 3874 We also read groups of the following items, one list element per 3875 item:: 3876 3877 localPeers //cb_config/stage/peer 3878 remotePeers //cb_config/stage/peer 3879 3880 The individual peer entries are parsed by L{_parsePeers}. 3881 3882 @param parentNode: Parent node to search beneath. 3883 3884 @return: C{StageConfig} object or C{None} if the section does not exist. 3885 @raise ValueError: If some filled-in value is invalid. 3886 """ 3887 stage = None 3888 sectionNode = readFirstChild(parentNode, "stage") 3889 if sectionNode is not None: 3890 stage = StageConfig() 3891 stage.targetDir = readString(sectionNode, "staging_dir") 3892 (stage.localPeers, stage.remotePeers) = Config._parsePeers(sectionNode) 3893 return stage
3894 _parseStage = staticmethod(_parseStage) 3895
3896 - def _parseStore(parentNode):
3897 """ 3898 Parses a store configuration section. 3899 3900 We read the following fields:: 3901 3902 sourceDir //cb_config/store/source_dir 3903 mediaType //cb_config/store/media_type 3904 deviceType //cb_config/store/device_type 3905 devicePath //cb_config/store/target_device 3906 deviceScsiId //cb_config/store/target_scsi_id 3907 driveSpeed //cb_config/store/drive_speed 3908 checkData //cb_config/store/check_data 3909 checkMedia //cb_config/store/check_media 3910 warnMidnite //cb_config/store/warn_midnite 3911 noEject //cb_config/store/no_eject 3912 3913 Blanking behavior configuration is parsed by the C{_parseBlankBehavior} 3914 method. 3915 3916 @param parentNode: Parent node to search beneath. 3917 3918 @return: C{StoreConfig} object or C{None} if the section does not exist. 3919 @raise ValueError: If some filled-in value is invalid. 3920 """ 3921 store = None 3922 sectionNode = readFirstChild(parentNode, "store") 3923 if sectionNode is not None: 3924 store = StoreConfig() 3925 store.sourceDir = readString(sectionNode, "source_dir") 3926 store.mediaType = readString(sectionNode, "media_type") 3927 store.deviceType = readString(sectionNode, "device_type") 3928 store.devicePath = readString(sectionNode, "target_device") 3929 store.deviceScsiId = readString(sectionNode, "target_scsi_id") 3930 store.driveSpeed = readInteger(sectionNode, "drive_speed") 3931 store.checkData = readBoolean(sectionNode, "check_data") 3932 store.checkMedia = readBoolean(sectionNode, "check_media") 3933 store.warnMidnite = readBoolean(sectionNode, "warn_midnite") 3934 store.noEject = readBoolean(sectionNode, "no_eject") 3935 store.blankBehavior = Config._parseBlankBehavior(sectionNode) 3936 return store
3937 _parseStore = staticmethod(_parseStore) 3938
3939 - def _parsePurge(parentNode):
3940 """ 3941 Parses a purge configuration section. 3942 3943 We read groups of the following items, one list element per 3944 item:: 3945 3946 purgeDirs //cb_config/purge/dir 3947 3948 The individual directory entries are parsed by L{_parsePurgeDirs}. 3949 3950 @param parentNode: Parent node to search beneath. 3951 3952 @return: C{PurgeConfig} object or C{None} if the section does not exist. 3953 @raise ValueError: If some filled-in value is invalid. 3954 """ 3955 purge = None 3956 sectionNode = readFirstChild(parentNode, "purge") 3957 if sectionNode is not None: 3958 purge = PurgeConfig() 3959 purge.purgeDirs = Config._parsePurgeDirs(sectionNode) 3960 return purge
3961 _parsePurge = staticmethod(_parsePurge) 3962
3963 - def _parseExtendedActions(parentNode):
3964 """ 3965 Reads extended actions data from immediately beneath the parent. 3966 3967 We read the following individual fields from each extended action:: 3968 3969 name name 3970 module module 3971 function function 3972 index index 3973 dependencies depends 3974 3975 Dependency information is parsed by the C{_parseDependencies} method. 3976 3977 @param parentNode: Parent node to search beneath. 3978 3979 @return: List of extended actions. 3980 @raise ValueError: If the data at the location can't be read 3981 """ 3982 lst = [] 3983 for entry in readChildren(parentNode, "action"): 3984 if isElement(entry): 3985 action = ExtendedAction() 3986 action.name = readString(entry, "name") 3987 action.module = readString(entry, "module") 3988 action.function = readString(entry, "function") 3989 action.index = readInteger(entry, "index") 3990 action.dependencies = Config._parseDependencies(entry) 3991 lst.append(action); 3992 if lst == []: 3993 lst = None 3994 return lst
3995 _parseExtendedActions = staticmethod(_parseExtendedActions) 3996
3997 - def _parseExclusions(parentNode):
3998 """ 3999 Reads exclusions data from immediately beneath the parent. 4000 4001 We read groups of the following items, one list element per item:: 4002 4003 absolute exclude/abs_path 4004 relative exclude/rel_path 4005 patterns exclude/pattern 4006 4007 If there are none of some pattern (i.e. no relative path items) then 4008 C{None} will be returned for that item in the tuple. 4009 4010 This method can be used to parse exclusions on both the collect 4011 configuration level and on the collect directory level within collect 4012 configuration. 4013 4014 @param parentNode: Parent node to search beneath. 4015 4016 @return: Tuple of (absolute, relative, patterns) exclusions. 4017 """ 4018 sectionNode = readFirstChild(parentNode, "exclude") 4019 if sectionNode is None: 4020 return (None, None, None) 4021 else: 4022 absolute = readStringList(sectionNode, "abs_path") 4023 relative = readStringList(sectionNode, "rel_path") 4024 patterns = readStringList(sectionNode, "pattern") 4025 return (absolute, relative, patterns)
4026 _parseExclusions = staticmethod(_parseExclusions) 4027
4028 - def _parseOverrides(parentNode):
4029 """ 4030 Reads a list of C{CommandOverride} objects from immediately beneath the parent. 4031 4032 We read the following individual fields:: 4033 4034 command command 4035 absolutePath abs_path 4036 4037 @param parentNode: Parent node to search beneath. 4038 4039 @return: List of C{CommandOverride} objects or C{None} if none are found. 4040 @raise ValueError: If some filled-in value is invalid. 4041 """ 4042 lst = [] 4043 for entry in readChildren(parentNode, "override"): 4044 if isElement(entry): 4045 override = CommandOverride() 4046 override.command = readString(entry, "command") 4047 override.absolutePath = readString(entry, "abs_path") 4048 lst.append(override) 4049 if lst == []: 4050 lst = None 4051 return lst
4052 _parseOverrides = staticmethod(_parseOverrides) 4053
4054 - def _parseHooks(parentNode):
4055 """ 4056 Reads a list of C{ActionHook} objects from immediately beneath the parent. 4057 4058 We read the following individual fields:: 4059 4060 action action 4061 command command 4062 4063 @param parentNode: Parent node to search beneath. 4064 4065 @return: List of C{ActionHook} objects or C{None} if none are found. 4066 @raise ValueError: If some filled-in value is invalid. 4067 """ 4068 lst = [] 4069 for entry in readChildren(parentNode, "pre_action_hook"): 4070 if isElement(entry): 4071 hook = PreActionHook() 4072 hook.action = readString(entry, "action") 4073 hook.command = readString(entry, "command") 4074 lst.append(hook) 4075 for entry in readChildren(parentNode, "post_action_hook"): 4076 if isElement(entry): 4077 hook = PostActionHook() 4078 hook.action = readString(entry, "action") 4079 hook.command = readString(entry, "command") 4080 lst.append(hook) 4081 if lst == []: 4082 lst = None 4083 return lst
4084 _parseHooks = staticmethod(_parseHooks) 4085
4086 - def _parseCollectFiles(parentNode):
4087 """ 4088 Reads a list of C{CollectFile} objects from immediately beneath the parent. 4089 4090 We read the following individual fields:: 4091 4092 absolutePath abs_path 4093 collectMode mode I{or} collect_mode 4094 archiveMode archive_mode 4095 4096 The collect mode is a special case. Just a C{mode} tag is accepted, but 4097 we prefer C{collect_mode} for consistency with the rest of the config 4098 file and to avoid confusion with the archive mode. If both are provided, 4099 only C{mode} will be used. 4100 4101 @param parentNode: Parent node to search beneath. 4102 4103 @return: List of C{CollectFile} objects or C{None} if none are found. 4104 @raise ValueError: If some filled-in value is invalid. 4105 """ 4106 lst = [] 4107 for entry in readChildren(parentNode, "file"): 4108 if isElement(entry): 4109 cfile = CollectFile() 4110 cfile.absolutePath = readString(entry, "abs_path") 4111 cfile.collectMode = readString(entry, "mode") 4112 if cfile.collectMode is None: 4113 cfile.collectMode = readString(entry, "collect_mode") 4114 cfile.archiveMode = readString(entry, "archive_mode") 4115 lst.append(cfile) 4116 if lst == []: 4117 lst = None 4118 return lst
4119 _parseCollectFiles = staticmethod(_parseCollectFiles) 4120
4121 - def _parseCollectDirs(parentNode):
4122 """ 4123 Reads a list of C{CollectDir} objects from immediately beneath the parent. 4124 4125 We read the following individual fields:: 4126 4127 absolutePath abs_path 4128 collectMode mode I{or} collect_mode 4129 archiveMode archive_mode 4130 ignoreFile ignore_file 4131 4132 The collect mode is a special case. Just a C{mode} tag is accepted for 4133 backwards compatibility, but we prefer C{collect_mode} for consistency 4134 with the rest of the config file and to avoid confusion with the archive 4135 mode. If both are provided, only C{mode} will be used. 4136 4137 We also read groups of the following items, one list element per 4138 item:: 4139 4140 absoluteExcludePaths exclude/abs_path 4141 relativeExcludePaths exclude/rel_path 4142 excludePatterns exclude/pattern 4143 4144 The exclusions are parsed by L{_parseExclusions}. 4145 4146 @param parentNode: Parent node to search beneath. 4147 4148 @return: List of C{CollectDir} objects or C{None} if none are found. 4149 @raise ValueError: If some filled-in value is invalid. 4150 """ 4151 lst = [] 4152 for entry in readChildren(parentNode, "dir"): 4153 if isElement(entry): 4154 cdir = CollectDir() 4155 cdir.absolutePath = readString(entry, "abs_path") 4156 cdir.collectMode = readString(entry, "mode") 4157 if cdir.collectMode is None: 4158 cdir.collectMode = readString(entry, "collect_mode") 4159 cdir.archiveMode = readString(entry, "archive_mode") 4160 cdir.ignoreFile = readString(entry, "ignore_file") 4161 (cdir.absoluteExcludePaths, cdir.relativeExcludePaths, cdir.excludePatterns) = Config._parseExclusions(entry) 4162 lst.append(cdir) 4163 if lst == []: 4164 lst = None 4165 return lst
4166 _parseCollectDirs = staticmethod(_parseCollectDirs) 4167
4168 - def _parsePurgeDirs(parentNode):
4169 """ 4170 Reads a list of C{PurgeDir} objects from immediately beneath the parent. 4171 4172 We read the following individual fields:: 4173 4174 absolutePath <baseExpr>/abs_path 4175 retainDays <baseExpr>/retain_days 4176 4177 @param parentNode: Parent node to search beneath. 4178 4179 @return: List of C{PurgeDir} objects or C{None} if none are found. 4180 @raise ValueError: If the data at the location can't be read 4181 """ 4182 lst = [] 4183 for entry in readChildren(parentNode, "dir"): 4184 if isElement(entry): 4185 cdir = PurgeDir() 4186 cdir.absolutePath = readString(entry, "abs_path") 4187 cdir.retainDays = readInteger(entry, "retain_days") 4188 lst.append(cdir) 4189 if lst == []: 4190 lst = None 4191 return lst
4192 _parsePurgeDirs = staticmethod(_parsePurgeDirs) 4193
4194 - def _parsePeers(parentNode):
4195 """ 4196 Reads remote and local peer data from immediately beneath the parent. 4197 4198 We read the following individual fields for both remote 4199 and local peers:: 4200 4201 name name 4202 collectDir collect_dir 4203 4204 We also read the following individual fields for remote peers 4205 only:: 4206 4207 remoteUser backup_user 4208 rcpCommand rcp_command 4209 4210 Additionally, the value in the C{type} field is used to determine whether 4211 this entry is a remote peer. If the type is C{"remote"}, it's a remote 4212 peer, and if the type is C{"local"}, it's a remote peer. 4213 4214 If there are none of one type of peer (i.e. no local peers) then C{None} 4215 will be returned for that item in the tuple. 4216 4217 @param parentNode: Parent node to search beneath. 4218 4219 @return: Tuple of (local, remote) peer lists. 4220 @raise ValueError: If the data at the location can't be read 4221 """ 4222 localPeers = [] 4223 remotePeers = [] 4224 for entry in readChildren(parentNode, "peer"): 4225 if isElement(entry): 4226 peerType = readString(entry, "type") 4227 if peerType == "local": 4228 localPeer = LocalPeer() 4229 localPeer.name = readString(entry, "name") 4230 localPeer.collectDir = readString(entry, "collect_dir") 4231 localPeers.append(localPeer) 4232 elif peerType == "remote": 4233 remotePeer = RemotePeer() 4234 remotePeer.name = readString(entry, "name") 4235 remotePeer.collectDir = readString(entry, "collect_dir") 4236 remotePeer.remoteUser = readString(entry, "backup_user") 4237 remotePeer.rcpCommand = readString(entry, "rcp_command") 4238 remotePeers.append(remotePeer) 4239 if localPeers == []: 4240 localPeers = None 4241 if remotePeers == []: 4242 remotePeers = None 4243 return (localPeers, remotePeers)
4244 _parsePeers = staticmethod(_parsePeers) 4245
4246 - def _parseDependencies(parentNode):
4247 """ 4248 Reads extended action dependency information from a parent node. 4249 4250 We read the following individual fields:: 4251 4252 runBefore depends/run_before 4253 runAfter depends/run_after 4254 4255 Each of these fields is a comma-separated list of action names. 4256 4257 The result is placed into an C{ActionDependencies} object. 4258 4259 If the dependencies parent node does not exist, C{None} will be returned. 4260 Otherwise, an C{ActionDependencies} object will always be created, even 4261 if it does not contain any actual dependencies in it. 4262 4263 @param parentNode: Parent node to search beneath. 4264 4265 @return: C{ActionDependencies} object or C{None}. 4266 @raise ValueError: If the data at the location can't be read 4267 """ 4268 sectionNode = readFirstChild(parentNode, "depends") 4269 if sectionNode is None: 4270 return None 4271 else: 4272 runBefore = readString(sectionNode, "run_before") 4273 runAfter = readString(sectionNode, "run_after") 4274 beforeList = Config._parseCommaSeparatedString(runBefore) 4275 afterList = Config._parseCommaSeparatedString(runAfter) 4276 return ActionDependencies(beforeList, afterList)
4277 _parseDependencies = staticmethod(_parseDependencies) 4278
4279 - def _parseCommaSeparatedString(commaString):
4280 """ 4281 Parses a list of values out of a comma-separated string. 4282 4283 The items in the list are split by comma, and then have whitespace 4284 stripped. As a special case, if C{commaString} is C{None}, then C{None} 4285 will be returned. 4286 4287 @param commaString: List of values in comma-separated string format. 4288 @return: Values from commaString split into a list, or C{None}. 4289 """ 4290 if commaString is None: 4291 return None 4292 else: 4293 pass1 = commaString.split(",") 4294 pass2 = [] 4295 for item in pass1: 4296 item = item.strip() 4297 if len(item) > 0: 4298 pass2.append(item) 4299 return pass2
4300 _parseCommaSeparatedString = staticmethod(_parseCommaSeparatedString) 4301
4302 - def _parseBlankBehavior(parentNode):
4303 """ 4304 Reads a single C{BlankBehavior} object from immediately beneath the parent. 4305 4306 We read the following individual fields:: 4307 4308 blankMode blank_behavior/mode 4309 blankFactor blank_behavior/factor 4310 4311 @param parentNode: Parent node to search beneath. 4312 4313 @return: C{BlankBehavior} object or C{None} if none if the section is not found 4314 @raise ValueError: If some filled-in value is invalid. 4315 """ 4316 blankBehavior = None 4317 sectionNode = readFirstChild(parentNode, "blank_behavior") 4318 if sectionNode is not None: 4319 blankBehavior = BlankBehavior() 4320 blankBehavior.blankMode = readString(sectionNode, "mode") 4321 blankBehavior.blankFactor = readString(sectionNode, "factor") 4322 return blankBehavior
4323 _parseBlankBehavior = staticmethod(_parseBlankBehavior) 4324 4325 4326 ######################################## 4327 # High-level methods for generating XML 4328 ######################################## 4329
4330 - def _extractXml(self):
4331 """ 4332 Internal method to extract configuration into an XML string. 4333 4334 This method assumes that the internal L{validate} method has been called 4335 prior to extracting the XML, if the caller cares. No validation will be 4336 done internally. 4337 4338 As a general rule, fields that are set to C{None} will be extracted into 4339 the document as empty tags. The same goes for container tags that are 4340 filled based on lists - if the list is empty or C{None}, the container 4341 tag will be empty. 4342 """ 4343 (xmlDom, parentNode) = createOutputDom() 4344 Config._addReference(xmlDom, parentNode, self.reference) 4345 Config._addExtensions(xmlDom, parentNode, self.extensions) 4346 Config._addOptions(xmlDom, parentNode, self.options) 4347 Config._addCollect(xmlDom, parentNode, self.collect) 4348 Config._addStage(xmlDom, parentNode, self.stage) 4349 Config._addStore(xmlDom, parentNode, self.store) 4350 Config._addPurge(xmlDom, parentNode, self.purge) 4351 xmlData = serializeDom(xmlDom) 4352 xmlDom.unlink() 4353 return xmlData
4354
4355 - def _addReference(xmlDom, parentNode, referenceConfig):
4356 """ 4357 Adds a <reference> configuration section as the next child of a parent. 4358 4359 We add the following fields to the document:: 4360 4361 author //cb_config/reference/author 4362 revision //cb_config/reference/revision 4363 description //cb_config/reference/description 4364 generator //cb_config/reference/generator 4365 4366 If C{referenceConfig} is C{None}, then no container will be added. 4367 4368 @param xmlDom: DOM tree as from L{createOutputDom}. 4369 @param parentNode: Parent that the section should be appended to. 4370 @param referenceConfig: Reference configuration section to be added to the document. 4371 """ 4372 if referenceConfig is not None: 4373 sectionNode = addContainerNode(xmlDom, parentNode, "reference") 4374 addStringNode(xmlDom, sectionNode, "author", referenceConfig.author) 4375 addStringNode(xmlDom, sectionNode, "revision", referenceConfig.revision) 4376 addStringNode(xmlDom, sectionNode, "description", referenceConfig.description) 4377 addStringNode(xmlDom, sectionNode, "generator", referenceConfig.generator)
4378 _addReference = staticmethod(_addReference) 4379
4380 - def _addExtensions(xmlDom, parentNode, extensionsConfig):
4381 """ 4382 Adds an <extensions> configuration section as the next child of a parent. 4383 4384 We add the following fields to the document:: 4385 4386 order_mode //cb_config/extensions/order_mode 4387 4388 We also add groups of the following items, one list element per item:: 4389 4390 actions //cb_config/extensions/action 4391 4392 The extended action entries are added by L{_addExtendedAction}. 4393 4394 If C{extensionsConfig} is C{None}, then no container will be added. 4395 4396 @param xmlDom: DOM tree as from L{createOutputDom}. 4397 @param parentNode: Parent that the section should be appended to. 4398 @param extensionsConfig: Extensions configuration section to be added to the document. 4399 """ 4400 if extensionsConfig is not None: 4401 sectionNode = addContainerNode(xmlDom, parentNode, "extensions") 4402 addStringNode(xmlDom, sectionNode, "order_mode", extensionsConfig.orderMode) 4403 if extensionsConfig.actions is not None: 4404 for action in extensionsConfig.actions: 4405 Config._addExtendedAction(xmlDom, sectionNode, action)
4406 _addExtensions = staticmethod(_addExtensions) 4407
4408 - def _addOptions(xmlDom, parentNode, optionsConfig):
4409 """ 4410 Adds a <options> configuration section as the next child of a parent. 4411 4412 We add the following fields to the document:: 4413 4414 startingDay //cb_config/options/starting_day 4415 workingDir //cb_config/options/working_dir 4416 backupUser //cb_config/options/backup_user 4417 backupGroup //cb_config/options/backup_group 4418 rcpCommand //cb_config/options/rcp_command 4419 4420 We also add groups of the following items, one list element per 4421 item:: 4422 4423 overrides //cb_config/options/override 4424 hooks //cb_config/options/pre_action_hook 4425 hooks //cb_config/options/post_action_hook 4426 4427 The individual override items are added by L{_addOverride}. The 4428 individual hook items are added by L{_addHook}. 4429 4430 If C{optionsConfig} is C{None}, then no container will be added. 4431 4432 @param xmlDom: DOM tree as from L{createOutputDom}. 4433 @param parentNode: Parent that the section should be appended to. 4434 @param optionsConfig: Options configuration section to be added to the document. 4435 """ 4436 if optionsConfig is not None: 4437 sectionNode = addContainerNode(xmlDom, parentNode, "options") 4438 addStringNode(xmlDom, sectionNode, "starting_day", optionsConfig.startingDay) 4439 addStringNode(xmlDom, sectionNode, "working_dir", optionsConfig.workingDir) 4440 addStringNode(xmlDom, sectionNode, "backup_user", optionsConfig.backupUser) 4441 addStringNode(xmlDom, sectionNode, "backup_group", optionsConfig.backupGroup) 4442 addStringNode(xmlDom, sectionNode, "rcp_command", optionsConfig.rcpCommand) 4443 if optionsConfig.overrides is not None: 4444 for override in optionsConfig.overrides: 4445 Config._addOverride(xmlDom, sectionNode, override) 4446 if optionsConfig.hooks is not None: 4447 for hook in optionsConfig.hooks: 4448 Config._addHook(xmlDom, sectionNode, hook)
4449 _addOptions = staticmethod(_addOptions) 4450
4451 - def _addCollect(xmlDom, parentNode, collectConfig):
4452 """ 4453 Adds a <collect> configuration section as the next child of a parent. 4454 4455 We add the following fields to the document:: 4456 4457 targetDir //cb_config/collect/collect_dir 4458 collectMode //cb_config/collect/collect_mode 4459 archiveMode //cb_config/collect/archive_mode 4460 ignoreFile //cb_config/collect/ignore_file 4461 4462 We also add groups of the following items, one list element per 4463 item:: 4464 4465 absoluteExcludePaths //cb_config/collect/exclude/abs_path 4466 excludePatterns //cb_config/collect/exclude/pattern 4467 collectFiles //cb_config/collect/file 4468 collectDirs //cb_config/collect/dir 4469 4470 The individual collect files are added by L{_addCollectFile} and 4471 individual collect directories are added by L{_addCollectDir}. 4472 4473 If C{collectConfig} is C{None}, then no container will be added. 4474 4475 @param xmlDom: DOM tree as from L{createOutputDom}. 4476 @param parentNode: Parent that the section should be appended to. 4477 @param collectConfig: Collect configuration section to be added to the document. 4478 """ 4479 if collectConfig is not None: 4480 sectionNode = addContainerNode(xmlDom, parentNode, "collect") 4481 addStringNode(xmlDom, sectionNode, "collect_dir", collectConfig.targetDir) 4482 addStringNode(xmlDom, sectionNode, "collect_mode", collectConfig.collectMode) 4483 addStringNode(xmlDom, sectionNode, "archive_mode", collectConfig.archiveMode) 4484 addStringNode(xmlDom, sectionNode, "ignore_file", collectConfig.ignoreFile) 4485 if ((collectConfig.absoluteExcludePaths is not None and collectConfig.absoluteExcludePaths != []) or 4486 (collectConfig.excludePatterns is not None and collectConfig.excludePatterns != [])): 4487 excludeNode = addContainerNode(xmlDom, sectionNode, "exclude") 4488 if collectConfig.absoluteExcludePaths is not None: 4489 for absolutePath in collectConfig.absoluteExcludePaths: 4490 addStringNode(xmlDom, excludeNode, "abs_path", absolutePath) 4491 if collectConfig.excludePatterns is not None: 4492 for pattern in collectConfig.excludePatterns: 4493 addStringNode(xmlDom, excludeNode, "pattern", pattern) 4494 if collectConfig.collectFiles is not None: 4495 for collectFile in collectConfig.collectFiles: 4496 Config._addCollectFile(xmlDom, sectionNode, collectFile) 4497 if collectConfig.collectDirs is not None: 4498 for collectDir in collectConfig.collectDirs: 4499 Config._addCollectDir(xmlDom, sectionNode, collectDir)
4500 _addCollect = staticmethod(_addCollect) 4501
4502 - def _addStage(xmlDom, parentNode, stageConfig):
4503 """ 4504 Adds a <stage> configuration section as the next child of a parent. 4505 4506 We add the following fields to the document:: 4507 4508 targetDir //cb_config/stage/staging_dir 4509 4510 We also add groups of the following items, one list element per 4511 item:: 4512 4513 localPeers //cb_config/stage/peer 4514 remotePeers //cb_config/stage/peer 4515 4516 The individual local and remote peer entries are added by 4517 L{_addLocalPeer} and L{_addRemotePeer}, respectively. 4518 4519 If C{stageConfig} is C{None}, then no container will be added. 4520 4521 @param xmlDom: DOM tree as from L{createOutputDom}. 4522 @param parentNode: Parent that the section should be appended to. 4523 @param stageConfig: Stage configuration section to be added to the document. 4524 """ 4525 if stageConfig is not None: 4526 sectionNode = addContainerNode(xmlDom, parentNode, "stage") 4527 addStringNode(xmlDom, sectionNode, "staging_dir", stageConfig.targetDir) 4528 if stageConfig.localPeers is not None: 4529 for localPeer in stageConfig.localPeers: 4530 Config._addLocalPeer(xmlDom, sectionNode, localPeer) 4531 if stageConfig.remotePeers is not None: 4532 for remotePeer in stageConfig.remotePeers: 4533 Config._addRemotePeer(xmlDom, sectionNode, remotePeer)
4534 _addStage = staticmethod(_addStage) 4535
4536 - def _addStore(xmlDom, parentNode, storeConfig):
4537 """ 4538 Adds a <store> configuration section as the next child of a parent. 4539 4540 We add the following fields to the document:: 4541 4542 sourceDir //cb_config/store/source_dir 4543 mediaType //cb_config/store/media_type 4544 deviceType //cb_config/store/device_type 4545 devicePath //cb_config/store/target_device 4546 deviceScsiId //cb_config/store/target_scsi_id 4547 driveSpeed //cb_config/store/drive_speed 4548 checkData //cb_config/store/check_data 4549 checkMedia //cb_config/store/check_media 4550 warnMidnite //cb_config/store/warn_midnite 4551 noEject //cb_config/store/no_eject 4552 4553 Blanking behavior configuration is added by the L{_addBlankBehavior} 4554 method. 4555 4556 If C{storeConfig} is C{None}, then no container will be added. 4557 4558 @param xmlDom: DOM tree as from L{createOutputDom}. 4559 @param parentNode: Parent that the section should be appended to. 4560 @param storeConfig: Store configuration section to be added to the document. 4561 """ 4562 if storeConfig is not None: 4563 sectionNode = addContainerNode(xmlDom, parentNode, "store") 4564 addStringNode(xmlDom, sectionNode, "source_dir", storeConfig.sourceDir) 4565 addStringNode(xmlDom, sectionNode, "media_type", storeConfig.mediaType) 4566 addStringNode(xmlDom, sectionNode, "device_type", storeConfig.deviceType) 4567 addStringNode(xmlDom, sectionNode, "target_device", storeConfig.devicePath) 4568 addStringNode(xmlDom, sectionNode, "target_scsi_id", storeConfig.deviceScsiId) 4569 addIntegerNode(xmlDom, sectionNode, "drive_speed", storeConfig.driveSpeed) 4570 addBooleanNode(xmlDom, sectionNode, "check_data", storeConfig.checkData) 4571 addBooleanNode(xmlDom, sectionNode, "check_media", storeConfig.checkMedia) 4572 addBooleanNode(xmlDom, sectionNode, "warn_midnite", storeConfig.warnMidnite) 4573 addBooleanNode(xmlDom, sectionNode, "no_eject", storeConfig.noEject) 4574 Config._addBlankBehavior(xmlDom, sectionNode, storeConfig.blankBehavior)
4575 _addStore = staticmethod(_addStore) 4576
4577 - def _addPurge(xmlDom, parentNode, purgeConfig):
4578 """ 4579 Adds a <purge> configuration section as the next child of a parent. 4580 4581 We add the following fields to the document:: 4582 4583 purgeDirs //cb_config/purge/dir 4584 4585 The individual directory entries are added by L{_addPurgeDir}. 4586 4587 If C{purgeConfig} is C{None}, then no container will be added. 4588 4589 @param xmlDom: DOM tree as from L{createOutputDom}. 4590 @param parentNode: Parent that the section should be appended to. 4591 @param purgeConfig: Purge configuration section to be added to the document. 4592 """ 4593 if purgeConfig is not None: 4594 sectionNode = addContainerNode(xmlDom, parentNode, "purge") 4595 if purgeConfig.purgeDirs is not None: 4596 for purgeDir in purgeConfig.purgeDirs: 4597 Config._addPurgeDir(xmlDom, sectionNode, purgeDir)
4598 _addPurge = staticmethod(_addPurge) 4599
4600 - def _addExtendedAction(xmlDom, parentNode, action):
4601 """ 4602 Adds an extended action container as the next child of a parent. 4603 4604 We add the following fields to the document:: 4605 4606 name action/name 4607 module action/module 4608 function action/function 4609 index action/index 4610 dependencies action/depends 4611 4612 Dependencies are added by the L{_addDependencies} method. 4613 4614 The <action> node itself is created as the next child of the parent node. 4615 This method only adds one action node. The parent must loop for each action 4616 in the C{ExtensionsConfig} object. 4617 4618 If C{action} is C{None}, this method call will be a no-op. 4619 4620 @param xmlDom: DOM tree as from L{createOutputDom}. 4621 @param parentNode: Parent that the section should be appended to. 4622 @param action: Purge directory to be added to the document. 4623 """ 4624 if action is not None: 4625 sectionNode = addContainerNode(xmlDom, parentNode, "action") 4626 addStringNode(xmlDom, sectionNode, "name", action.name) 4627 addStringNode(xmlDom, sectionNode, "module", action.module) 4628 addStringNode(xmlDom, sectionNode, "function", action.function) 4629 addIntegerNode(xmlDom, sectionNode, "index", action.index) 4630 Config._addDependencies(xmlDom, sectionNode, action.dependencies)
4631 _addExtendedAction = staticmethod(_addExtendedAction) 4632
4633 - def _addOverride(xmlDom, parentNode, override):
4634 """ 4635 Adds a command override container as the next child of a parent. 4636 4637 We add the following fields to the document:: 4638 4639 command override/command 4640 absolutePath override/abs_path 4641 4642 The <override> node itself is created as the next child of the parent 4643 node. This method only adds one override node. The parent must loop for 4644 each override in the C{OptionsConfig} object. 4645 4646 If C{override} is C{None}, this method call will be a no-op. 4647 4648 @param xmlDom: DOM tree as from L{createOutputDom}. 4649 @param parentNode: Parent that the section should be appended to. 4650 @param override: Command override to be added to the document. 4651 """ 4652 if override is not None: 4653 sectionNode = addContainerNode(xmlDom, parentNode, "override") 4654 addStringNode(xmlDom, sectionNode, "command", override.command) 4655 addStringNode(xmlDom, sectionNode, "abs_path", override.absolutePath)
4656 _addOverride = staticmethod(_addOverride) 4657
4658 - def _addHook(xmlDom, parentNode, hook):
4659 """ 4660 Adds an action hook container as the next child of a parent. 4661 4662 The behavior varies depending on the value of the C{before} and C{after} 4663 flags on the hook. If the C{before} flag is set, it's a pre-action hook, 4664 and we'll add the following fields:: 4665 4666 action pre_action_hook/action 4667 command pre_action_hook/command 4668 4669 If the C{after} flag is set, it's a post-action hook, and we'll add the 4670 following fields:: 4671 4672 action post_action_hook/action 4673 command post_action_hook/command 4674 4675 The <pre_action_hook> or <post_action_hook> node itself is created as the 4676 next child of the parent node. This method only adds one hook node. The 4677 parent must loop for each hook in the C{OptionsConfig} object. 4678 4679 If C{hook} is C{None}, this method call will be a no-op. 4680 4681 @param xmlDom: DOM tree as from L{createOutputDom}. 4682 @param parentNode: Parent that the section should be appended to. 4683 @param hook: Command hook to be added to the document. 4684 """ 4685 if hook is not None: 4686 if hook.before: 4687 sectionNode = addContainerNode(xmlDom, parentNode, "pre_action_hook") 4688 else: 4689 sectionNode = addContainerNode(xmlDom, parentNode, "post_action_hook") 4690 addStringNode(xmlDom, sectionNode, "action", hook.action) 4691 addStringNode(xmlDom, sectionNode, "command", hook.command)
4692 _addHook = staticmethod(_addHook) 4693
4694 - def _addCollectFile(xmlDom, parentNode, collectFile):
4695 """ 4696 Adds a collect file container as the next child of a parent. 4697 4698 We add the following fields to the document:: 4699 4700 absolutePath dir/abs_path 4701 collectMode dir/collect_mode 4702 archiveMode dir/archive_mode 4703 4704 Note that for consistency with collect directory handling we'll only emit 4705 the preferred C{collect_mode} tag. 4706 4707 The <file> node itself is created as the next child of the parent node. 4708 This method only adds one collect file node. The parent must loop 4709 for each collect file in the C{CollectConfig} object. 4710 4711 If C{collectFile} is C{None}, this method call will be a no-op. 4712 4713 @param xmlDom: DOM tree as from L{createOutputDom}. 4714 @param parentNode: Parent that the section should be appended to. 4715 @param collectFile: Collect file to be added to the document. 4716 """ 4717 if collectFile is not None: 4718 sectionNode = addContainerNode(xmlDom, parentNode, "file") 4719 addStringNode(xmlDom, sectionNode, "abs_path", collectFile.absolutePath) 4720 addStringNode(xmlDom, sectionNode, "collect_mode", collectFile.collectMode) 4721 addStringNode(xmlDom, sectionNode, "archive_mode", collectFile.archiveMode)
4722 _addCollectFile = staticmethod(_addCollectFile) 4723
4724 - def _addCollectDir(xmlDom, parentNode, collectDir):
4725 """ 4726 Adds a collect directory container as the next child of a parent. 4727 4728 We add the following fields to the document:: 4729 4730 absolutePath dir/abs_path 4731 collectMode dir/collect_mode 4732 archiveMode dir/archive_mode 4733 ignoreFile dir/ignore_file 4734 4735 Note that an original XML document might have listed the collect mode 4736 using the C{mode} tag, since we accept both C{collect_mode} and C{mode}. 4737 However, here we'll only emit the preferred C{collect_mode} tag. 4738 4739 We also add groups of the following items, one list element per item:: 4740 4741 absoluteExcludePaths dir/exclude/abs_path 4742 relativeExcludePaths dir/exclude/rel_path 4743 excludePatterns dir/exclude/pattern 4744 4745 The <dir> node itself is created as the next child of the parent node. 4746 This method only adds one collect directory node. The parent must loop 4747 for each collect directory in the C{CollectConfig} object. 4748 4749 If C{collectDir} is C{None}, this method call will be a no-op. 4750 4751 @param xmlDom: DOM tree as from L{createOutputDom}. 4752 @param parentNode: Parent that the section should be appended to. 4753 @param collectDir: Collect directory to be added to the document. 4754 """ 4755 if collectDir is not None: 4756 sectionNode = addContainerNode(xmlDom, parentNode, "dir") 4757 addStringNode(xmlDom, sectionNode, "abs_path", collectDir.absolutePath) 4758 addStringNode(xmlDom, sectionNode, "collect_mode", collectDir.collectMode) 4759 addStringNode(xmlDom, sectionNode, "archive_mode", collectDir.archiveMode) 4760 addStringNode(xmlDom, sectionNode, "ignore_file", collectDir.ignoreFile) 4761 if ((collectDir.absoluteExcludePaths is not None and collectDir.absoluteExcludePaths != []) or 4762 (collectDir.relativeExcludePaths is not None and collectDir.relativeExcludePaths != []) or 4763 (collectDir.excludePatterns is not None and collectDir.excludePatterns != [])): 4764 excludeNode = addContainerNode(xmlDom, sectionNode, "exclude") 4765 if collectDir.absoluteExcludePaths is not None: 4766 for absolutePath in collectDir.absoluteExcludePaths: 4767 addStringNode(xmlDom, excludeNode, "abs_path", absolutePath) 4768 if collectDir.relativeExcludePaths is not None: 4769 for relativePath in collectDir.relativeExcludePaths: 4770 addStringNode(xmlDom, excludeNode, "rel_path", relativePath) 4771 if collectDir.excludePatterns is not None: 4772 for pattern in collectDir.excludePatterns: 4773 addStringNode(xmlDom, excludeNode, "pattern", pattern)
4774 _addCollectDir = staticmethod(_addCollectDir) 4775
4776 - def _addLocalPeer(xmlDom, parentNode, localPeer):
4777 """ 4778 Adds a local peer container as the next child of a parent. 4779 4780 We add the following fields to the document:: 4781 4782 name peer/name 4783 collectDir peer/collect_dir 4784 4785 Additionally, C{peer/type} is filled in with C{"local"}, since this is a 4786 local peer. 4787 4788 The <peer> node itself is created as the next child of the parent node. 4789 This method only adds one peer node. The parent must loop for each peer 4790 in the C{StageConfig} object. 4791 4792 If C{localPeer} is C{None}, this method call will be a no-op. 4793 4794 @param xmlDom: DOM tree as from L{createOutputDom}. 4795 @param parentNode: Parent that the section should be appended to. 4796 @param localPeer: Purge directory to be added to the document. 4797 """ 4798 if localPeer is not None: 4799 sectionNode = addContainerNode(xmlDom, parentNode, "peer") 4800 addStringNode(xmlDom, sectionNode, "name", localPeer.name) 4801 addStringNode(xmlDom, sectionNode, "type", "local") 4802 addStringNode(xmlDom, sectionNode, "collect_dir", localPeer.collectDir)
4803 _addLocalPeer = staticmethod(_addLocalPeer) 4804
4805 - def _addRemotePeer(xmlDom, parentNode, remotePeer):
4806 """ 4807 Adds a remote peer container as the next child of a parent. 4808 4809 We add the following fields to the document:: 4810 4811 name peer/name 4812 collectDir peer/collect_dir 4813 remoteUser peer/backup_user 4814 rcpCommand peer/rcp_command 4815 4816 Additionally, C{peer/type} is filled in with C{"remote"}, since this is a 4817 remote peer. 4818 4819 The <peer> node itself is created as the next child of the parent node. 4820 This method only adds one peer node. The parent must loop for each peer 4821 in the C{StageConfig} object. 4822 4823 If C{remotePeer} is C{None}, this method call will be a no-op. 4824 4825 @param xmlDom: DOM tree as from L{createOutputDom}. 4826 @param parentNode: Parent that the section should be appended to. 4827 @param remotePeer: Purge directory to be added to the document. 4828 """ 4829 if remotePeer is not None: 4830 sectionNode = addContainerNode(xmlDom, parentNode, "peer") 4831 addStringNode(xmlDom, sectionNode, "name", remotePeer.name) 4832 addStringNode(xmlDom, sectionNode, "type", "remote") 4833 addStringNode(xmlDom, sectionNode, "collect_dir", remotePeer.collectDir) 4834 addStringNode(xmlDom, sectionNode, "backup_user", remotePeer.remoteUser) 4835 addStringNode(xmlDom, sectionNode, "rcp_command", remotePeer.rcpCommand)
4836 _addRemotePeer = staticmethod(_addRemotePeer) 4837
4838 - def _addPurgeDir(xmlDom, parentNode, purgeDir):
4839 """ 4840 Adds a purge directory container as the next child of a parent. 4841 4842 We add the following fields to the document:: 4843 4844 absolutePath dir/abs_path 4845 retainDays dir/retain_days 4846 4847 The <dir> node itself is created as the next child of the parent node. 4848 This method only adds one purge directory node. The parent must loop for 4849 each purge directory in the C{PurgeConfig} object. 4850 4851 If C{purgeDir} is C{None}, this method call will be a no-op. 4852 4853 @param xmlDom: DOM tree as from L{createOutputDom}. 4854 @param parentNode: Parent that the section should be appended to. 4855 @param purgeDir: Purge directory to be added to the document. 4856 """ 4857 if purgeDir is not None: 4858 sectionNode = addContainerNode(xmlDom, parentNode, "dir") 4859 addStringNode(xmlDom, sectionNode, "abs_path", purgeDir.absolutePath) 4860 addIntegerNode(xmlDom, sectionNode, "retain_days", purgeDir.retainDays)
4861 _addPurgeDir = staticmethod(_addPurgeDir) 4862
4863 - def _addDependencies(xmlDom, parentNode, dependencies):
4864 """ 4865 Adds a extended action dependencies to parent node. 4866 4867 We add the following fields to the document:: 4868 4869 runBefore depends/run_before 4870 runAfter depends/run_after 4871 4872 If C{dependencies} is C{None}, this method call will be a no-op. 4873 4874 @param xmlDom: DOM tree as from L{createOutputDom}. 4875 @param parentNode: Parent that the section should be appended to. 4876 @param dependencies: C{ActionDependencies} object to be added to the document 4877 """ 4878 if dependencies is not None: 4879 sectionNode = addContainerNode(xmlDom, parentNode, "depends") 4880 runBefore = Config._buildCommaSeparatedString(dependencies.beforeList) 4881 runAfter = Config._buildCommaSeparatedString(dependencies.afterList) 4882 addStringNode(xmlDom, sectionNode, "run_before", runBefore) 4883 addStringNode(xmlDom, sectionNode, "run_after", runAfter)
4884 _addDependencies = staticmethod(_addDependencies) 4885
4886 - def _buildCommaSeparatedString(valueList):
4887 """ 4888 Creates a comma-separated string from a list of values. 4889 4890 As a special case, if C{valueList} is C{None}, then C{None} will be 4891 returned. 4892 4893 @param valueList: List of values to be placed into a string 4894 4895 @return: Values from valueList as a comma-separated string. 4896 """ 4897 if valueList is None: 4898 return None 4899 return ",".join(valueList)
4900 _buildCommaSeparatedString = staticmethod(_buildCommaSeparatedString) 4901
4902 - def _addBlankBehavior(xmlDom, parentNode, blankBehavior):
4903 """ 4904 Adds a blanking behavior container as the next child of a parent. 4905 4906 We add the following fields to the document:: 4907 4908 blankMode blank_behavior/mode 4909 blankFactor blank_behavior/factor 4910 4911 The <blank_behavior> node itself is created as the next child of the 4912 parent node. 4913 4914 If C{blankBehavior} is C{None}, this method call will be a no-op. 4915 4916 @param xmlDom: DOM tree as from L{createOutputDom}. 4917 @param parentNode: Parent that the section should be appended to. 4918 @param blankBehavior: Blanking behavior to be added to the document. 4919 """ 4920 if blankBehavior is not None: 4921 sectionNode = addContainerNode(xmlDom, parentNode, "blank_behavior") 4922 addStringNode(xmlDom, sectionNode, "mode", blankBehavior.blankMode) 4923 addStringNode(xmlDom, sectionNode, "factor", blankBehavior.blankFactor)
4924 _addBlankBehavior = staticmethod(_addBlankBehavior) 4925 4926 4927 ################################################# 4928 # High-level methods used for validating content 4929 ################################################# 4930
4931 - def _validateContents(self):
4932 """ 4933 Validates configuration contents per rules discussed in module 4934 documentation. 4935 4936 This is the second pass at validation. It ensures that any filled-in 4937 section contains valid data. Any sections which is not set to C{None} is 4938 validated per the rules for that section, laid out in the module 4939 documentation (above). 4940 4941 @raise ValueError: If configuration is invalid. 4942 """ 4943 self._validateReference() 4944 self._validateExtensions() 4945 self._validateOptions() 4946 self._validateCollect() 4947 self._validateStage() 4948 self._validateStore() 4949 self._validatePurge()
4950
4951 - def _validateReference(self):
4952 """ 4953 Validates reference configuration. 4954 There are currently no reference-related validations. 4955 @raise ValueError: If reference configuration is invalid. 4956 """ 4957 pass
4958
4959 - def _validateExtensions(self):
4960 """ 4961 Validates extensions configuration. 4962 4963 The list of actions may be either C{None} or an empty list C{[]} if 4964 desired. Each extended action must include a name, a module, and a 4965 function. 4966 4967 Then, if the order mode is None or "index", an index is required; and if 4968 the order mode is "dependency", dependency information is required. 4969 4970 @raise ValueError: If reference configuration is invalid. 4971 """ 4972 if self.extensions is not None: 4973 if self.extensions.actions is not None: 4974 names = [] 4975 for action in self.extensions.actions: 4976 if action.name is None: 4977 raise ValueError("Each extended action must set a name.") 4978 names.append(action.name) 4979 if action.module is None: 4980 raise ValueError("Each extended action must set a module.") 4981 if action.function is None: 4982 raise ValueError("Each extended action must set a function.") 4983 if self.extensions.orderMode is None or self.extensions.orderMode == "index": 4984 if action.index is None: 4985 raise ValueError("Each extended action must set an index, based on order mode.") 4986 elif self.extensions.orderMode == "dependency": 4987 if action.dependencies is None: 4988 raise ValueError("Each extended action must set dependency information, based on order mode.") 4989 Config._checkUnique("Duplicate extension names exist:", names)
4990
4991 - def _validateOptions(self):
4992 """ 4993 Validates options configuration. 4994 4995 All fields must be filled in. The rcp command is used as a default value 4996 for all remote peers in the staging section. Remote peers can also rely 4997 on the backup user as the default remote user name if they choose. 4998 4999 @raise ValueError: If reference configuration is invalid. 5000 """ 5001 if self.options is not None: 5002 if self.options.startingDay is None: 5003 raise ValueError("Options section starting day must be filled in.") 5004 if self.options.workingDir is None: 5005 raise ValueError("Options section working directory must be filled in.") 5006 if self.options.backupUser is None: 5007 raise ValueError("Options section backup user must be filled in.") 5008 if self.options.backupGroup is None: 5009 raise ValueError("Options section backup group must be filled in.") 5010 if self.options.rcpCommand is None: 5011 raise ValueError("Options section remote copy command must be filled in.")
5012
5013 - def _validateCollect(self):
5014 """ 5015 Validates collect configuration. 5016 5017 The target directory must be filled in. The collect mode, archive mode 5018 and ignore file are all optional. The list of absolute paths to exclude 5019 and patterns to exclude may be either C{None} or an empty list C{[]} if 5020 desired. 5021 5022 Each collect directory entry must contain an absolute path to collect, 5023 and then must either be able to take collect mode, archive mode and 5024 ignore file configuration from the parent C{CollectConfig} object, or 5025 must set each value on its own. The list of absolute paths to exclude, 5026 relative paths to exclude and patterns to exclude may be either C{None} 5027 or an empty list C{[]} if desired. Any list of absolute paths to exclude 5028 or patterns to exclude will be combined with the same list in the 5029 C{CollectConfig} object to make the complete list for a given directory. 5030 5031 @raise ValueError: If collect configuration is invalid. 5032 """ 5033 if self.collect is not None: 5034 if self.collect.targetDir is None: 5035 raise ValueError("Collect section target directory must be filled in.") 5036 if self.collect.collectFiles is not None: 5037 for collectFile in self.collect.collectFiles: 5038 if collectFile.absolutePath is None: 5039 raise ValueError("Each collect file must set an absolute path.") 5040 if self.collect.collectMode is None and collectFile.collectMode is None: 5041 raise ValueError("Collect mode must either be set in parent collect section or individual collect file.") 5042 if self.collect.archiveMode is None and collectFile.archiveMode is None: 5043 raise ValueError("Archive mode must either be set in parent collect section or individual collect file.") 5044 if self.collect.collectDirs is not None: 5045 for collectDir in self.collect.collectDirs: 5046 if collectDir.absolutePath is None: 5047 raise ValueError("Each collect directory must set an absolute path.") 5048 if self.collect.collectMode is None and collectDir.collectMode is None: 5049 raise ValueError("Collect mode must either be set in parent collect section or individual collect directory.") 5050 if self.collect.archiveMode is None and collectDir.archiveMode is None: 5051 raise ValueError("Archive mode must either be set in parent collect section or individual collect directory.") 5052 if self.collect.ignoreFile is None and collectDir.ignoreFile is None: 5053 raise ValueError("Ignore file must either be set in parent collect section or individual collect directory.")
5054
5055 - def _validateStage(self):
5056 """ 5057 Validates stage configuration. 5058 5059 The target directory must be filled in. There must be at least one peer 5060 (remote or local) between the two lists of peers. A list with no entries 5061 can be either C{None} or an empty list C{[]} if desired. 5062 5063 Local peers must be completely filled in, including both name and collect 5064 directory. Remote peers must also fill in the name and collect 5065 directory, but can leave the remote user and rcp command unset. In this 5066 case, the remote user is assumed to match the backup user from the 5067 options section and rcp command is taken directly from the options 5068 section. 5069 5070 @raise ValueError: If stage configuration is invalid. 5071 """ 5072 if self.stage is not None: 5073 if self.stage.targetDir is None: 5074 raise ValueError("Stage section target directory must be filled in.") 5075 if self.stage.localPeers is None and self.stage.remotePeers is None: 5076 raise ValueError("Stage section must contain at least one backup peer.") 5077 if self.stage.localPeers is None and self.stage.remotePeers is not None: 5078 if len(self.stage.remotePeers) < 1: 5079 raise ValueError("Stage section must contain at least one backup peer.") 5080 elif self.stage.localPeers is not None and self.stage.remotePeers is None: 5081 if len(self.stage.localPeers) < 1: 5082 raise ValueError("Stage section must contain at least one backup peer.") 5083 elif self.stage.localPeers is not None and self.stage.remotePeers is not None: 5084 if len(self.stage.localPeers) + len(self.stage.remotePeers) < 1: 5085 raise ValueError("Stage section must contain at least one backup peer.") 5086 names = [] 5087 if self.stage.localPeers is not None: 5088 for localPeer in self.stage.localPeers: 5089 if localPeer.name is None: 5090 raise ValueError("Local peers must set a name.") 5091 names.append(localPeer.name) 5092 if localPeer.collectDir is None: 5093 raise ValueError("Local peers must set a collect directory.") 5094 if self.stage.remotePeers is not None: 5095 for remotePeer in self.stage.remotePeers: 5096 if remotePeer.name is None: 5097 raise ValueError("Remote peers must set a name.") 5098 names.append(remotePeer.name) 5099 if remotePeer.collectDir is None: 5100 raise ValueError("Remote peers must set a collect directory.") 5101 if (self.options is None or self.options.backupUser is None) and remotePeer.remoteUser is None: # redundant 5102 raise ValueError("Remote user must either be set in options section or individual remote peer.") 5103 if (self.options is None or self.options.rcpCommand is None) and remotePeer.rcpCommand is None: # redundant 5104 raise ValueError("Remote copy command must either be set in options section or individual remote peer.") 5105 Config._checkUnique("Duplicate peer names exist:", names)
5106
5107 - def _validateStore(self):
5108 """ 5109 Validates store configuration. 5110 5111 The device type, drive speed, and blanking behavior are optional. All 5112 other values are required. Missing booleans will be set to defaults. 5113 5114 If blanking behavior is provided, then both a blanking mode and a 5115 blanking factor are required. 5116 5117 The image writer functionality in the C{writer} module is supposed to be 5118 able to handle a device speed of C{None}. 5119 5120 Any caller which needs a "real" (non-C{None}) value for the device type 5121 can use C{DEFAULT_DEVICE_TYPE}, which is guaranteed to be sensible. 5122 5123 This is also where we make sure that the media type -- which is already a 5124 valid type -- matches up properly with the device type. 5125 5126 @raise ValueError: If store configuration is invalid. 5127 """ 5128 if self.store is not None: 5129 if self.store.sourceDir is None: 5130 raise ValueError("Store section source directory must be filled in.") 5131 if self.store.mediaType is None: 5132 raise ValueError("Store section media type must be filled in.") 5133 if self.store.devicePath is None: 5134 raise ValueError("Store section device path must be filled in.") 5135 if self.store.deviceType == None or self.store.deviceType == "cdwriter": 5136 if self.store.mediaType not in VALID_CD_MEDIA_TYPES: 5137 raise ValueError("Media type must match device type.") 5138 elif self.store.deviceType == "dvdwriter": 5139 if self.store.mediaType not in VALID_DVD_MEDIA_TYPES: 5140 raise ValueError("Media type must match device type.") 5141 if self.store.blankBehavior is not None: 5142 if self.store.blankBehavior.blankMode is None and self.store.blankBehavior.blankFactor is None: 5143 raise ValueError("If blanking behavior is provided, all values must be filled in.")
5144
5145 - def _validatePurge(self):
5146 """ 5147 Validates purge configuration. 5148 5149 The list of purge directories may be either C{None} or an empty list 5150 C{[]} if desired. All purge directories must contain a path and a retain 5151 days value. 5152 5153 @raise ValueError: If purge configuration is invalid. 5154 """ 5155 if self.purge is not None: 5156 if self.purge.purgeDirs is not None: 5157 for purgeDir in self.purge.purgeDirs: 5158 if purgeDir.absolutePath is None: 5159 raise ValueError("Each purge directory must set an absolute path.") 5160 if purgeDir.retainDays is None: 5161 raise ValueError("Each purge directory must set a retain days value.")
5162 5163 5164 ############################################## 5165 # Utility methods used for validating content 5166 ############################################## 5167
5168 - def _checkUnique(prefix, values):
5169 """ 5170 Checks that all values are unique. 5171 5172 The values list is checked for duplicate values. If there are 5173 duplicates, an exception is thrown. All duplicate values are listed in 5174 the exception. 5175 5176 @param prefix: Prefix to use in the thrown exception 5177 @param values: List of values to check 5178 5179 @raise ValueError: If there are duplicates in the list 5180 """ 5181 values.sort() 5182 duplicates = [] 5183 for i in range(1, len(values)): 5184 if values[i-1] == values[i]: 5185 duplicates.append(values[i]) 5186 if duplicates: 5187 raise ValueError("%s %s" % (prefix, duplicates))
5188 _checkUnique = staticmethod(_checkUnique)
5189