1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 """
39 Provides configuration-related objects.
40
41 Summary
42 =======
43
44 Cedar Backup stores all of its configuration in an XML document typically
45 called C{cback3.conf}. The standard location for this document is in
46 C{/etc}, but users can specify a different location if they want to.
47
48 The C{Config} class is a Python object representation of a Cedar Backup XML
49 configuration file. The representation is two-way: XML data can be used to
50 create a C{Config} object, and then changes to the object can be propogated
51 back to disk. A C{Config} object can even be used to create a configuration
52 file from scratch programmatically.
53
54 The C{Config} class is intended to be the only Python-language interface to
55 Cedar Backup configuration on disk. Cedar Backup will use the class as its
56 internal representation of configuration, and applications external to Cedar
57 Backup itself (such as a hypothetical third-party configuration tool written
58 in Python or a third party extension module) should also use the class when
59 they need to read and write configuration files.
60
61 Backwards Compatibility
62 =======================
63
64 The configuration file format has changed between Cedar Backup 1.x and Cedar
65 Backup 2.x. Any Cedar Backup 1.x configuration file is also a valid Cedar
66 Backup 2.x configuration file. However, it doesn't work to go the other
67 direction, as the 2.x configuration files contains additional configuration
68 is not accepted by older versions of the software.
69
70 XML Configuration Structure
71 ===========================
72
73 A C{Config} object can either be created "empty", or can be created based on
74 XML input (either in the form of a string or read in from a file on disk).
75 Generally speaking, the XML input I{must} result in a C{Config} object which
76 passes the validations laid out below in the I{Validation} section.
77
78 An XML configuration file is composed of seven sections:
79
80 - I{reference}: specifies reference information about the file (author, revision, etc)
81 - I{extensions}: specifies mappings to Cedar Backup extensions (external code)
82 - I{options}: specifies global configuration options
83 - I{peers}: specifies the set of peers in a master's backup pool
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 except the rsh command. The rcp and rsh
162 commands are used as default values for all remote peers. Remote peers can
163 also rely on the backup user as the default remote user name if they choose.
164
165 I{Peers Validations}
166
167 Local peers must be completely filled in, including both name and collect
168 directory. Remote peers must also fill in the name and collect directory,
169 but can leave the remote user and rcp command unset. In this case, the
170 remote user is assumed to match the backup user from the options section and
171 rcp command is taken directly from the options section.
172
173 I{Collect Validations}
174
175 The target directory must be filled in. The collect mode, archive mode and
176 ignore file are all optional. The list of absolute paths to exclude and
177 patterns to exclude may be either C{None} or an empty list C{[]} if desired.
178
179 Each collect directory entry must contain an absolute path to collect, and
180 then must either be able to take collect mode, archive mode and ignore file
181 configuration from the parent C{CollectConfig} object, or must set each
182 value on its own. The list of absolute paths to exclude, relative paths to
183 exclude and patterns to exclude may be either C{None} or an empty list C{[]}
184 if desired. Any list of absolute paths to exclude or patterns to exclude
185 will be combined with the same list in the C{CollectConfig} object to make
186 the complete list for a given directory.
187
188 I{Stage Validations}
189
190 The target directory must be filled in. There must be at least one peer
191 (remote or local) between the two lists of peers. A list with no entries
192 can be either C{None} or an empty list C{[]} if desired.
193
194 If a set of peers is provided, this configuration completely overrides
195 configuration in the peers configuration section, and the same validations
196 apply.
197
198 I{Store Validations}
199
200 The device type and drive speed are optional, and all other values are
201 required (missing booleans will be set to defaults, which is OK).
202
203 The image writer functionality in the C{writer} module is supposed to be
204 able to handle a device speed of C{None}. Any caller which needs a "real"
205 (non-C{None}) value for the device type can use C{DEFAULT_DEVICE_TYPE},
206 which is guaranteed to be sensible.
207
208 I{Purge Validations}
209
210 The list of purge directories may be either C{None} or an empty list C{[]}
211 if desired. All purge directories must contain a path and a retain days
212 value.
213
214 @sort: ActionDependencies, ActionHook, PreActionHook, PostActionHook,
215 ExtendedAction, CommandOverride, CollectFile, CollectDir, PurgeDir, LocalPeer,
216 RemotePeer, ReferenceConfig, ExtensionsConfig, OptionsConfig, PeersConfig,
217 CollectConfig, StageConfig, StoreConfig, PurgeConfig, Config,
218 DEFAULT_DEVICE_TYPE, DEFAULT_MEDIA_TYPE,
219 VALID_DEVICE_TYPES, VALID_MEDIA_TYPES,
220 VALID_COLLECT_MODES, VALID_ARCHIVE_MODES,
221 VALID_ORDER_MODES
222
223 @var DEFAULT_DEVICE_TYPE: The default device type.
224 @var DEFAULT_MEDIA_TYPE: The default media type.
225 @var VALID_DEVICE_TYPES: List of valid device types.
226 @var VALID_MEDIA_TYPES: List of valid media types.
227 @var VALID_COLLECT_MODES: List of valid collect modes.
228 @var VALID_COMPRESS_MODES: List of valid compress modes.
229 @var VALID_ARCHIVE_MODES: List of valid archive modes.
230 @var VALID_ORDER_MODES: List of valid extension order modes.
231
232 @author: Kenneth J. Pronovici <pronovic@ieee.org>
233 """
234
235
236
237
238
239
240 import os
241 import re
242 import logging
243 from functools import total_ordering
244
245
246 from CedarBackup3.writers.util import validateScsiId, validateDriveSpeed
247 from CedarBackup3.util import UnorderedList, AbsolutePathList, ObjectTypeList, parseCommaSeparatedString
248 from CedarBackup3.util import RegexMatchList, RegexList, encodePath, checkUnique
249 from CedarBackup3.util import convertSize, UNIT_BYTES, UNIT_KBYTES, UNIT_MBYTES, UNIT_GBYTES
250 from CedarBackup3.xmlutil import isElement, readChildren, readFirstChild
251 from CedarBackup3.xmlutil import readStringList, readString, readInteger, readBoolean
252 from CedarBackup3.xmlutil import addContainerNode, addStringNode, addIntegerNode, addBooleanNode
253 from CedarBackup3.xmlutil import createInputDom, createOutputDom, serializeDom
254
255
256
257
258
259
260 logger = logging.getLogger("CedarBackup3.log.config")
261
262 DEFAULT_DEVICE_TYPE = "cdwriter"
263 DEFAULT_MEDIA_TYPE = "cdrw-74"
264
265 VALID_DEVICE_TYPES = [ "cdwriter", "dvdwriter", ]
266 VALID_CD_MEDIA_TYPES = [ "cdr-74", "cdrw-74", "cdr-80", "cdrw-80", ]
267 VALID_DVD_MEDIA_TYPES = [ "dvd+r", "dvd+rw", ]
268 VALID_MEDIA_TYPES = VALID_CD_MEDIA_TYPES + VALID_DVD_MEDIA_TYPES
269 VALID_COLLECT_MODES = [ "daily", "weekly", "incr", ]
270 VALID_ARCHIVE_MODES = [ "tar", "targz", "tarbz2", ]
271 VALID_COMPRESS_MODES = [ "none", "gzip", "bzip2", ]
272 VALID_ORDER_MODES = [ "index", "dependency", ]
273 VALID_BLANK_MODES = [ "daily", "weekly", ]
274 VALID_BYTE_UNITS = [ UNIT_BYTES, UNIT_KBYTES, UNIT_MBYTES, UNIT_GBYTES, ]
275 VALID_FAILURE_MODES = [ "none", "all", "daily", "weekly", ]
276
277 REWRITABLE_MEDIA_TYPES = [ "cdrw-74", "cdrw-80", "dvd+rw", ]
278
279 ACTION_NAME_REGEX = r"^[a-z0-9]*$"
280
281
282
283
284
285
286 @total_ordering
287 -class ByteQuantity(object):
288
289 """
290 Class representing a byte quantity.
291
292 A byte quantity has both a quantity and a byte-related unit. Units are
293 maintained using the constants from util.py.
294
295 The quantity is maintained internally as a string so that issues of
296 precision can be avoided. It really isn't possible to store a floating
297 point number here while being able to losslessly translate back and forth
298 between XML and object representations. (Perhaps the Python 2.4 Decimal
299 class would have been an option, but I originally wanted to stay compatible
300 with Python 2.3.)
301
302 Even though the quantity is maintained as a string, the string must be in a
303 valid floating point positive number. Technically, any floating point
304 string format supported by Python is allowble. However, it does not make
305 sense to have a negative quantity of bytes in this context.
306
307 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__,
308 quantity, units
309 """
310
311 - def __init__(self, quantity=None, units=None):
312 """
313 Constructor for the C{ByteQuantity} class.
314
315 @param quantity: Quantity of bytes, as string ("1.25")
316 @param units: Unit of bytes, one of VALID_BYTE_UNITS
317
318 @raise ValueError: If one of the values is invalid.
319 """
320 self._quantity = None
321 self._units = None
322 self.quantity = quantity
323 self.units = units
324
326 """
327 Official string representation for class instance.
328 """
329 return "ByteQuantity(%s, %s)" % (self.quantity, self.units)
330
332 """
333 Informal string representation for class instance.
334 """
335 return self.__repr__()
336
338 """Equals operator, iplemented in terms of original Python 2 compare operator."""
339 return self.__cmp__(other) == 0
340
342 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
343 return self.__cmp__(other) < 0
344
346 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
347 return self.__cmp__(other) > 0
348
350 """
351 Original Python 2 comparison operator.
352 Lists within this class are "unordered" for equality comparisons.
353 @param other: Other object to compare to.
354 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other.
355 """
356 if other is None:
357 return 1
358 if self.quantity != other.quantity:
359 if float(self.quantity or 0.0) < float(other.quantity or 0.0):
360 return -1
361 else:
362 return 1
363 if self.units != other.units:
364 if str(self.units or "") < str(other.units or ""):
365 return -1
366 else:
367 return 1
368 return 0
369
371 """
372 Property target used to set the quantity
373 The value must be a non-empty string if it is not C{None}.
374 @raise ValueError: If the value is an empty string.
375 @raise ValueError: If the value is not a valid floating point number
376 @raise ValueError: If the value is less than zero
377 """
378 if value is not None:
379 if len(value) < 1:
380 raise ValueError("Quantity must be a non-empty string.")
381 floatValue = float(value)
382 if floatValue < 0.0:
383 raise ValueError("Quantity cannot be negative.")
384 self._quantity = value
385
387 """
388 Property target used to get the quantity.
389 """
390 return self._quantity
391
393 """
394 Property target used to set the units value.
395 If not C{None}, the units value must be one of the values in L{VALID_BYTE_UNITS}.
396 @raise ValueError: If the value is not valid.
397 """
398 if value is not None:
399 if value not in VALID_BYTE_UNITS:
400 raise ValueError("Units value must be one of %s." % VALID_BYTE_UNITS)
401 self._units = value
402
404 """
405 Property target used to get the units value.
406 """
407 return self._units
408
410 """
411 Property target used to return the byte quantity as a floating point number.
412 If there is no quantity set, then a value of 0.0 is returned.
413 """
414 if self.quantity is not None and self.units is not None:
415 return convertSize(self.quantity, self.units, UNIT_BYTES)
416 return 0.0
417
418 quantity = property(_getQuantity, _setQuantity, None, doc="Byte quantity, as a string")
419 units = property(_getUnits, _setUnits, None, doc="Units for byte quantity, for instance UNIT_BYTES")
420 bytes = property(_getBytes, None, None, doc="Byte quantity, as a floating point number.")
421
429
430 """
431 Class representing dependencies associated with an extended action.
432
433 Execution ordering for extended actions is done in one of two ways: either by using
434 index values (lower index gets run first) or by having the extended action specify
435 dependencies in terms of other named actions. This class encapsulates the dependency
436 information for an extended action.
437
438 The following restrictions exist on data in this class:
439
440 - Any action name must be a non-empty string matching C{ACTION_NAME_REGEX}
441
442 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__,
443 beforeList, afterList
444 """
445
446 - def __init__(self, beforeList=None, afterList=None):
447 """
448 Constructor for the C{ActionDependencies} class.
449
450 @param beforeList: List of named actions that this action must be run before
451 @param afterList: List of named actions that this action must be run after
452
453 @raise ValueError: If one of the values is invalid.
454 """
455 self._beforeList = None
456 self._afterList = None
457 self.beforeList = beforeList
458 self.afterList = afterList
459
461 """
462 Official string representation for class instance.
463 """
464 return "ActionDependencies(%s, %s)" % (self.beforeList, self.afterList)
465
467 """
468 Informal string representation for class instance.
469 """
470 return self.__repr__()
471
473 """Equals operator, iplemented in terms of original Python 2 compare operator."""
474 return self.__cmp__(other) == 0
475
477 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
478 return self.__cmp__(other) < 0
479
481 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
482 return self.__cmp__(other) > 0
483
485 """
486 Original Python 2 comparison operator.
487 @param other: Other object to compare to.
488 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other.
489 """
490 if other is None:
491 return 1
492 if self.beforeList != other.beforeList:
493 if self.beforeList < other.beforeList:
494 return -1
495 else:
496 return 1
497 if self.afterList != other.afterList:
498 if self.afterList < other.afterList:
499 return -1
500 else:
501 return 1
502 return 0
503
505 """
506 Property target used to set the "run before" list.
507 Either the value must be C{None} or each element must be a string matching ACTION_NAME_REGEX.
508 @raise ValueError: If the value does not match the regular expression.
509 """
510 if value is None:
511 self._beforeList = None
512 else:
513 try:
514 saved = self._beforeList
515 self._beforeList = RegexMatchList(ACTION_NAME_REGEX, emptyAllowed=False, prefix="Action name")
516 self._beforeList.extend(value)
517 except Exception as e:
518 self._beforeList = saved
519 raise e
520
522 """
523 Property target used to get the "run before" list.
524 """
525 return self._beforeList
526
528 """
529 Property target used to set the "run after" list.
530 Either the value must be C{None} or each element must be a string matching ACTION_NAME_REGEX.
531 @raise ValueError: If the value does not match the regular expression.
532 """
533 if value is None:
534 self._afterList = None
535 else:
536 try:
537 saved = self._afterList
538 self._afterList = RegexMatchList(ACTION_NAME_REGEX, emptyAllowed=False, prefix="Action name")
539 self._afterList.extend(value)
540 except Exception as e:
541 self._afterList = saved
542 raise e
543
545 """
546 Property target used to get the "run after" list.
547 """
548 return self._afterList
549
550 beforeList = property(_getBeforeList, _setBeforeList, None, "List of named actions that this action must be run before.")
551 afterList = property(_getAfterList, _setAfterList, None, "List of named actions that this action must be run after.")
552
553
554
555
556
557
558 @total_ordering
559 -class ActionHook(object):
560
561 """
562 Class representing a hook associated with an action.
563
564 A hook associated with an action is a shell command to be executed either
565 before or after a named action is executed.
566
567 The following restrictions exist on data in this class:
568
569 - The action name must be a non-empty string matching C{ACTION_NAME_REGEX}
570 - The shell command must be a non-empty string.
571
572 The internal C{before} and C{after} instance variables are always set to
573 False in this parent class.
574
575 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__, action,
576 command, before, after
577 """
578
579 - def __init__(self, action=None, command=None):
580 """
581 Constructor for the C{ActionHook} class.
582
583 @param action: Action this hook is associated with
584 @param command: Shell command to execute
585
586 @raise ValueError: If one of the values is invalid.
587 """
588 self._action = None
589 self._command = None
590 self._before = False
591 self._after = False
592 self.action = action
593 self.command = command
594
596 """
597 Official string representation for class instance.
598 """
599 return "ActionHook(%s, %s, %s, %s)" % (self.action, self.command, self.before, self.after)
600
602 """
603 Informal string representation for class instance.
604 """
605 return self.__repr__()
606
608 """Equals operator, iplemented in terms of original Python 2 compare operator."""
609 return self.__cmp__(other) == 0
610
612 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
613 return self.__cmp__(other) < 0
614
616 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
617 return self.__cmp__(other) > 0
618
620 """
621 Original Python 2 comparison operator.
622 @param other: Other object to compare to.
623 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other.
624 """
625 if other is None:
626 return 1
627 if self.action != other.action:
628 if str(self.action or "") < str(other.action or ""):
629 return -1
630 else:
631 return 1
632 if self.command != other.command:
633 if str(self.command or "") < str(other.command or ""):
634 return -1
635 else:
636 return 1
637 if self.before != other.before:
638 if self.before < other.before:
639 return -1
640 else:
641 return 1
642 if self.after != other.after:
643 if self.after < other.after:
644 return -1
645 else:
646 return 1
647 return 0
648
650 """
651 Property target used to set the action name.
652 The value must be a non-empty string if it is not C{None}.
653 It must also consist only of lower-case letters and digits.
654 @raise ValueError: If the value is an empty string.
655 """
656 pattern = re.compile(ACTION_NAME_REGEX)
657 if value is not None:
658 if len(value) < 1:
659 raise ValueError("The action name must be a non-empty string.")
660 if not pattern.search(value):
661 raise ValueError("The action name must consist of only lower-case letters and digits.")
662 self._action = value
663
665 """
666 Property target used to get the action name.
667 """
668 return self._action
669
671 """
672 Property target used to set the command.
673 The value must be a non-empty string if it is not C{None}.
674 @raise ValueError: If the value is an empty string.
675 """
676 if value is not None:
677 if len(value) < 1:
678 raise ValueError("The command must be a non-empty string.")
679 self._command = value
680
682 """
683 Property target used to get the command.
684 """
685 return self._command
686
688 """
689 Property target used to get the before flag.
690 """
691 return self._before
692
694 """
695 Property target used to get the after flag.
696 """
697 return self._after
698
699 action = property(_getAction, _setAction, None, "Action this hook is associated with.")
700 command = property(_getCommand, _setCommand, None, "Shell command to execute.")
701 before = property(_getBefore, None, None, "Indicates whether command should be executed before action.")
702 after = property(_getAfter, None, None, "Indicates whether command should be executed after action.")
703
706
707 """
708 Class representing a pre-action hook associated with an action.
709
710 A hook associated with an action is a shell command to be executed either
711 before or after a named action is executed. In this case, a pre-action hook
712 is executed before the named action.
713
714 The following restrictions exist on data in this class:
715
716 - The action name must be a non-empty string consisting of lower-case letters and digits.
717 - The shell command must be a non-empty string.
718
719 The internal C{before} instance variable is always set to True in this
720 class.
721
722 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__, action,
723 command, before, after
724 """
725
726 - def __init__(self, action=None, command=None):
727 """
728 Constructor for the C{PreActionHook} class.
729
730 @param action: Action this hook is associated with
731 @param command: Shell command to execute
732
733 @raise ValueError: If one of the values is invalid.
734 """
735 ActionHook.__init__(self, action, command)
736 self._before = True
737
739 """
740 Official string representation for class instance.
741 """
742 return "PreActionHook(%s, %s, %s, %s)" % (self.action, self.command, self.before, self.after)
743
744 @total_ordering
745 -class PostActionHook(ActionHook):
746
747 """
748 Class representing a pre-action hook associated with an action.
749
750 A hook associated with an action is a shell command to be executed either
751 before or after a named action is executed. In this case, a post-action hook
752 is executed after the named action.
753
754 The following restrictions exist on data in this class:
755
756 - The action name must be a non-empty string consisting of lower-case letters and digits.
757 - The shell command must be a non-empty string.
758
759 The internal C{before} instance variable is always set to True in this
760 class.
761
762 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__, action,
763 command, before, after
764 """
765
766 - def __init__(self, action=None, command=None):
767 """
768 Constructor for the C{PostActionHook} class.
769
770 @param action: Action this hook is associated with
771 @param command: Shell command to execute
772
773 @raise ValueError: If one of the values is invalid.
774 """
775 ActionHook.__init__(self, action, command)
776 self._after = True
777
778 - def __repr__(self):
779 """
780 Official string representation for class instance.
781 """
782 return "PostActionHook(%s, %s, %s, %s)" % (self.action, self.command, self.before, self.after)
783
784
785
786
787
788
789 @total_ordering
790 -class BlankBehavior(object):
791
792 """
793 Class representing optimized store-action media blanking behavior.
794
795 The following restrictions exist on data in this class:
796
797 - The blanking mode must be a one of the values in L{VALID_BLANK_MODES}
798 - The blanking factor must be a positive floating point number
799
800 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__,
801 blankMode, blankFactor
802 """
803
804 - def __init__(self, blankMode=None, blankFactor=None):
805 """
806 Constructor for the C{BlankBehavior} class.
807
808 @param blankMode: Blanking mode
809 @param blankFactor: Blanking factor
810
811 @raise ValueError: If one of the values is invalid.
812 """
813 self._blankMode = None
814 self._blankFactor = None
815 self.blankMode = blankMode
816 self.blankFactor = blankFactor
817
819 """
820 Official string representation for class instance.
821 """
822 return "BlankBehavior(%s, %s)" % (self.blankMode, self.blankFactor)
823
825 """
826 Informal string representation for class instance.
827 """
828 return self.__repr__()
829
831 """Equals operator, iplemented in terms of original Python 2 compare operator."""
832 return self.__cmp__(other) == 0
833
835 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
836 return self.__cmp__(other) < 0
837
839 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
840 return self.__cmp__(other) > 0
841
843 """
844 Original Python 2 comparison operator.
845 @param other: Other object to compare to.
846 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other.
847 """
848 if other is None:
849 return 1
850 if self.blankMode != other.blankMode:
851 if str(self.blankMode or "") < str(other.blankMode or ""):
852 return -1
853 else:
854 return 1
855 if self.blankFactor != other.blankFactor:
856 if float(self.blankFactor or 0.0) < float(other.blankFactor or 0.0):
857 return -1
858 else:
859 return 1
860 return 0
861
863 """
864 Property target used to set the blanking mode.
865 The value must be one of L{VALID_BLANK_MODES}.
866 @raise ValueError: If the value is not valid.
867 """
868 if value is not None:
869 if value not in VALID_BLANK_MODES:
870 raise ValueError("Blanking mode must be one of %s." % VALID_BLANK_MODES)
871 self._blankMode = value
872
874 """
875 Property target used to get the blanking mode.
876 """
877 return self._blankMode
878
880 """
881 Property target used to set the blanking factor.
882 The value must be a non-empty string if it is not C{None}.
883 @raise ValueError: If the value is an empty string.
884 @raise ValueError: If the value is not a valid floating point number
885 @raise ValueError: If the value is less than zero
886 """
887 if value is not None:
888 if len(value) < 1:
889 raise ValueError("Blanking factor must be a non-empty string.")
890 floatValue = float(value)
891 if floatValue < 0.0:
892 raise ValueError("Blanking factor cannot be negative.")
893 self._blankFactor = value
894
896 """
897 Property target used to get the blanking factor.
898 """
899 return self._blankFactor
900
901 blankMode = property(_getBlankMode, _setBlankMode, None, "Blanking mode")
902 blankFactor = property(_getBlankFactor, _setBlankFactor, None, "Blanking factor")
903
911
912 """
913 Class representing an extended action.
914
915 Essentially, an extended action needs to allow the following to happen::
916
917 exec("from %s import %s" % (module, function))
918 exec("%s(action, configPath")" % function)
919
920 The following restrictions exist on data in this class:
921
922 - The action name must be a non-empty string consisting of lower-case letters and digits.
923 - The module must be a non-empty string and a valid Python identifier.
924 - The function must be an on-empty string and a valid Python identifier.
925 - If set, the index must be a positive integer.
926 - If set, the dependencies attribute must be an C{ActionDependencies} object.
927
928 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__, name,
929 module, function, index, dependencies
930 """
931
932 - def __init__(self, name=None, module=None, function=None, index=None, dependencies=None):
933 """
934 Constructor for the C{ExtendedAction} class.
935
936 @param name: Name of the extended action
937 @param module: Name of the module containing the extended action function
938 @param function: Name of the extended action function
939 @param index: Index of action, used for execution ordering
940 @param dependencies: Dependencies for action, used for execution ordering
941
942 @raise ValueError: If one of the values is invalid.
943 """
944 self._name = None
945 self._module = None
946 self._function = None
947 self._index = None
948 self._dependencies = None
949 self.name = name
950 self.module = module
951 self.function = function
952 self.index = index
953 self.dependencies = dependencies
954
956 """
957 Official string representation for class instance.
958 """
959 return "ExtendedAction(%s, %s, %s, %s, %s)" % (self.name, self.module, self.function, self.index, self.dependencies)
960
962 """
963 Informal string representation for class instance.
964 """
965 return self.__repr__()
966
968 """Equals operator, iplemented in terms of original Python 2 compare operator."""
969 return self.__cmp__(other) == 0
970
972 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
973 return self.__cmp__(other) < 0
974
976 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
977 return self.__cmp__(other) > 0
978
980 """
981 Original Python 2 comparison operator.
982 @param other: Other object to compare to.
983 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other.
984 """
985 if other is None:
986 return 1
987 if self.name != other.name:
988 if str(self.name or "") < str(other.name or ""):
989 return -1
990 else:
991 return 1
992 if self.module != other.module:
993 if str(self.module or "") < str(other.module or ""):
994 return -1
995 else:
996 return 1
997 if self.function != other.function:
998 if str(self.function or "") < str(other.function or ""):
999 return -1
1000 else:
1001 return 1
1002 if self.index != other.index:
1003 if int(self.index or 0) < int(other.index or 0):
1004 return -1
1005 else:
1006 return 1
1007 if self.dependencies != other.dependencies:
1008 if self.dependencies < other.dependencies:
1009 return -1
1010 else:
1011 return 1
1012 return 0
1013
1015 """
1016 Property target used to set the action name.
1017 The value must be a non-empty string if it is not C{None}.
1018 It must also consist only of lower-case letters and digits.
1019 @raise ValueError: If the value is an empty string.
1020 """
1021 pattern = re.compile(ACTION_NAME_REGEX)
1022 if value is not None:
1023 if len(value) < 1:
1024 raise ValueError("The action name must be a non-empty string.")
1025 if not pattern.search(value):
1026 raise ValueError("The action name must consist of only lower-case letters and digits.")
1027 self._name = value
1028
1030 """
1031 Property target used to get the action name.
1032 """
1033 return self._name
1034
1036 """
1037 Property target used to set the module name.
1038 The value must be a non-empty string if it is not C{None}.
1039 It must also be a valid Python identifier.
1040 @raise ValueError: If the value is an empty string.
1041 """
1042 pattern = re.compile(r"^([A-Za-z_][A-Za-z0-9_]*)(\.[A-Za-z_][A-Za-z0-9_]*)*$")
1043 if value is not None:
1044 if len(value) < 1:
1045 raise ValueError("The module name must be a non-empty string.")
1046 if not pattern.search(value):
1047 raise ValueError("The module name must be a valid Python identifier.")
1048 self._module = value
1049
1051 """
1052 Property target used to get the module name.
1053 """
1054 return self._module
1055
1057 """
1058 Property target used to set the function name.
1059 The value must be a non-empty string if it is not C{None}.
1060 It must also be a valid Python identifier.
1061 @raise ValueError: If the value is an empty string.
1062 """
1063 pattern = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
1064 if value is not None:
1065 if len(value) < 1:
1066 raise ValueError("The function name must be a non-empty string.")
1067 if not pattern.search(value):
1068 raise ValueError("The function name must be a valid Python identifier.")
1069 self._function = value
1070
1072 """
1073 Property target used to get the function name.
1074 """
1075 return self._function
1076
1078 """
1079 Property target used to set the action index.
1080 The value must be an integer >= 0.
1081 @raise ValueError: If the value is not valid.
1082 """
1083 if value is None:
1084 self._index = None
1085 else:
1086 try:
1087 value = int(value)
1088 except TypeError:
1089 raise ValueError("Action index value must be an integer >= 0.")
1090 if value < 0:
1091 raise ValueError("Action index value must be an integer >= 0.")
1092 self._index = value
1093
1095 """
1096 Property target used to get the action index.
1097 """
1098 return self._index
1099
1101 """
1102 Property target used to set the action dependencies information.
1103 If not C{None}, the value must be a C{ActionDependecies} object.
1104 @raise ValueError: If the value is not a C{ActionDependencies} object.
1105 """
1106 if value is None:
1107 self._dependencies = None
1108 else:
1109 if not isinstance(value, ActionDependencies):
1110 raise ValueError("Value must be a C{ActionDependencies} object.")
1111 self._dependencies = value
1112
1114 """
1115 Property target used to get action dependencies information.
1116 """
1117 return self._dependencies
1118
1119 name = property(_getName, _setName, None, "Name of the extended action.")
1120 module = property(_getModule, _setModule, None, "Name of the module containing the extended action function.")
1121 function = property(_getFunction, _setFunction, None, "Name of the extended action function.")
1122 index = property(_getIndex, _setIndex, None, "Index of action, used for execution ordering.")
1123 dependencies = property(_getDependencies, _setDependencies, None, "Dependencies for action, used for execution ordering.")
1124
1125
1126
1127
1128
1129
1130 @total_ordering
1131 -class CommandOverride(object):
1132
1133 """
1134 Class representing a piece of Cedar Backup command override configuration.
1135
1136 The following restrictions exist on data in this class:
1137
1138 - The absolute path must be absolute
1139
1140 @note: Lists within this class are "unordered" for equality comparisons.
1141
1142 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__,
1143 command, absolutePath
1144 """
1145
1146 - def __init__(self, command=None, absolutePath=None):
1147 """
1148 Constructor for the C{CommandOverride} class.
1149
1150 @param command: Name of command to be overridden.
1151 @param absolutePath: Absolute path of the overrridden command.
1152
1153 @raise ValueError: If one of the values is invalid.
1154 """
1155 self._command = None
1156 self._absolutePath = None
1157 self.command = command
1158 self.absolutePath = absolutePath
1159
1161 """
1162 Official string representation for class instance.
1163 """
1164 return "CommandOverride(%s, %s)" % (self.command, self.absolutePath)
1165
1167 """
1168 Informal string representation for class instance.
1169 """
1170 return self.__repr__()
1171
1173 """Equals operator, iplemented in terms of original Python 2 compare operator."""
1174 return self.__cmp__(other) == 0
1175
1177 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
1178 return self.__cmp__(other) < 0
1179
1181 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
1182 return self.__cmp__(other) > 0
1183
1185 """
1186 Original Python 2 comparison operator.
1187 @param other: Other object to compare to.
1188 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other.
1189 """
1190 if other is None:
1191 return 1
1192 if self.command != other.command:
1193 if str(self.command or "") < str(other.command or ""):
1194 return -1
1195 else:
1196 return 1
1197 if self.absolutePath != other.absolutePath:
1198 if str(self.absolutePath or "") < str(other.absolutePath or ""):
1199 return -1
1200 else:
1201 return 1
1202 return 0
1203
1205 """
1206 Property target used to set the command.
1207 The value must be a non-empty string if it is not C{None}.
1208 @raise ValueError: If the value is an empty string.
1209 """
1210 if value is not None:
1211 if len(value) < 1:
1212 raise ValueError("The command must be a non-empty string.")
1213 self._command = value
1214
1216 """
1217 Property target used to get the command.
1218 """
1219 return self._command
1220
1222 """
1223 Property target used to set the absolute path.
1224 The value must be an absolute path if it is not C{None}.
1225 It does not have to exist on disk at the time of assignment.
1226 @raise ValueError: If the value is not an absolute path.
1227 @raise ValueError: If the value cannot be encoded properly.
1228 """
1229 if value is not None:
1230 if not os.path.isabs(value):
1231 raise ValueError("Not an absolute path: [%s]" % value)
1232 self._absolutePath = encodePath(value)
1233
1235 """
1236 Property target used to get the absolute path.
1237 """
1238 return self._absolutePath
1239
1240 command = property(_getCommand, _setCommand, None, doc="Name of command to be overridden.")
1241 absolutePath = property(_getAbsolutePath, _setAbsolutePath, None, doc="Absolute path of the overrridden command.")
1242
1243
1244
1245
1246
1247
1248 @total_ordering
1249 -class CollectFile(object):
1250
1251 """
1252 Class representing a Cedar Backup collect file.
1253
1254 The following restrictions exist on data in this class:
1255
1256 - Absolute paths must be absolute
1257 - The collect mode must be one of the values in L{VALID_COLLECT_MODES}.
1258 - The archive mode must be one of the values in L{VALID_ARCHIVE_MODES}.
1259
1260 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__,
1261 absolutePath, collectMode, archiveMode
1262 """
1263
1264 - def __init__(self, absolutePath=None, collectMode=None, archiveMode=None):
1265 """
1266 Constructor for the C{CollectFile} class.
1267
1268 @param absolutePath: Absolute path of the file to collect.
1269 @param collectMode: Overridden collect mode for this file.
1270 @param archiveMode: Overridden archive mode for this file.
1271
1272 @raise ValueError: If one of the values is invalid.
1273 """
1274 self._absolutePath = None
1275 self._collectMode = None
1276 self._archiveMode = None
1277 self.absolutePath = absolutePath
1278 self.collectMode = collectMode
1279 self.archiveMode = archiveMode
1280
1286
1288 """
1289 Informal string representation for class instance.
1290 """
1291 return self.__repr__()
1292
1294 """Equals operator, iplemented in terms of original Python 2 compare operator."""
1295 return self.__cmp__(other) == 0
1296
1298 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
1299 return self.__cmp__(other) < 0
1300
1302 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
1303 return self.__cmp__(other) > 0
1304
1306 """
1307 Original Python 2 comparison operator.
1308 @param other: Other object to compare to.
1309 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other.
1310 """
1311 if other is None:
1312 return 1
1313 if self.absolutePath != other.absolutePath:
1314 if str(self.absolutePath or "") < str(other.absolutePath or ""):
1315 return -1
1316 else:
1317 return 1
1318 if self.collectMode != other.collectMode:
1319 if str(self.collectMode or "") < str(other.collectMode or ""):
1320 return -1
1321 else:
1322 return 1
1323 if self.archiveMode != other.archiveMode:
1324 if str(self.archiveMode or "") < str(other.archiveMode or ""):
1325 return -1
1326 else:
1327 return 1
1328 return 0
1329
1331 """
1332 Property target used to set the absolute path.
1333 The value must be an absolute path if it is not C{None}.
1334 It does not have to exist on disk at the time of assignment.
1335 @raise ValueError: If the value is not an absolute path.
1336 @raise ValueError: If the value cannot be encoded properly.
1337 """
1338 if value is not None:
1339 if not os.path.isabs(value):
1340 raise ValueError("Not an absolute path: [%s]" % value)
1341 self._absolutePath = encodePath(value)
1342
1344 """
1345 Property target used to get the absolute path.
1346 """
1347 return self._absolutePath
1348
1350 """
1351 Property target used to set the collect mode.
1352 If not C{None}, the mode must be one of the values in L{VALID_COLLECT_MODES}.
1353 @raise ValueError: If the value is not valid.
1354 """
1355 if value is not None:
1356 if value not in VALID_COLLECT_MODES:
1357 raise ValueError("Collect mode must be one of %s." % VALID_COLLECT_MODES)
1358 self._collectMode = value
1359
1361 """
1362 Property target used to get the collect mode.
1363 """
1364 return self._collectMode
1365
1367 """
1368 Property target used to set the archive mode.
1369 If not C{None}, the mode must be one of the values in L{VALID_ARCHIVE_MODES}.
1370 @raise ValueError: If the value is not valid.
1371 """
1372 if value is not None:
1373 if value not in VALID_ARCHIVE_MODES:
1374 raise ValueError("Archive mode must be one of %s." % VALID_ARCHIVE_MODES)
1375 self._archiveMode = value
1376
1378 """
1379 Property target used to get the archive mode.
1380 """
1381 return self._archiveMode
1382
1383 absolutePath = property(_getAbsolutePath, _setAbsolutePath, None, doc="Absolute path of the file to collect.")
1384 collectMode = property(_getCollectMode, _setCollectMode, None, doc="Overridden collect mode for this file.")
1385 archiveMode = property(_getArchiveMode, _setArchiveMode, None, doc="Overridden archive mode for this file.")
1386
1387
1388
1389
1390
1391
1392 @total_ordering
1393 -class CollectDir(object):
1394
1395 """
1396 Class representing a Cedar Backup collect directory.
1397
1398 The following restrictions exist on data in this class:
1399
1400 - Absolute paths must be absolute
1401 - The collect mode must be one of the values in L{VALID_COLLECT_MODES}.
1402 - The archive mode must be one of the values in L{VALID_ARCHIVE_MODES}.
1403 - The ignore file must be a non-empty string.
1404
1405 For the C{absoluteExcludePaths} list, validation is accomplished through the
1406 L{util.AbsolutePathList} list implementation that overrides common list
1407 methods and transparently does the absolute path validation for us.
1408
1409 @note: Lists within this class are "unordered" for equality comparisons.
1410
1411 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__, absolutePath, collectMode,
1412 archiveMode, ignoreFile, linkDepth, dereference, absoluteExcludePaths,
1413 relativeExcludePaths, excludePatterns
1414 """
1415
1416 - def __init__(self, absolutePath=None, collectMode=None, archiveMode=None, ignoreFile=None,
1417 absoluteExcludePaths=None, relativeExcludePaths=None, excludePatterns=None,
1418 linkDepth=None, dereference=False, recursionLevel=None):
1419 """
1420 Constructor for the C{CollectDir} class.
1421
1422 @param absolutePath: Absolute path of the directory to collect.
1423 @param collectMode: Overridden collect mode for this directory.
1424 @param archiveMode: Overridden archive mode for this directory.
1425 @param ignoreFile: Overidden ignore file name for this directory.
1426 @param linkDepth: Maximum at which soft links should be followed.
1427 @param dereference: Whether to dereference links that are followed.
1428 @param absoluteExcludePaths: List of absolute paths to exclude.
1429 @param relativeExcludePaths: List of relative paths to exclude.
1430 @param excludePatterns: List of regular expression patterns to exclude.
1431
1432 @raise ValueError: If one of the values is invalid.
1433 """
1434 self._absolutePath = None
1435 self._collectMode = None
1436 self._archiveMode = None
1437 self._ignoreFile = None
1438 self._linkDepth = None
1439 self._dereference = None
1440 self._recursionLevel = None
1441 self._absoluteExcludePaths = None
1442 self._relativeExcludePaths = None
1443 self._excludePatterns = None
1444 self.absolutePath = absolutePath
1445 self.collectMode = collectMode
1446 self.archiveMode = archiveMode
1447 self.ignoreFile = ignoreFile
1448 self.linkDepth = linkDepth
1449 self.dereference = dereference
1450 self.recursionLevel = recursionLevel
1451 self.absoluteExcludePaths = absoluteExcludePaths
1452 self.relativeExcludePaths = relativeExcludePaths
1453 self.excludePatterns = excludePatterns
1454
1456 """
1457 Official string representation for class instance.
1458 """
1459 return "CollectDir(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" % (self.absolutePath, self.collectMode,
1460 self.archiveMode, self.ignoreFile,
1461 self.absoluteExcludePaths,
1462 self.relativeExcludePaths,
1463 self.excludePatterns,
1464 self.linkDepth, self.dereference,
1465 self.recursionLevel)
1466
1468 """
1469 Informal string representation for class instance.
1470 """
1471 return self.__repr__()
1472
1474 """Equals operator, iplemented in terms of original Python 2 compare operator."""
1475 return self.__cmp__(other) == 0
1476
1478 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
1479 return self.__cmp__(other) < 0
1480
1482 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
1483 return self.__cmp__(other) > 0
1484
1545
1547 """
1548 Property target used to set the absolute path.
1549 The value must be an absolute path if it is not C{None}.
1550 It does not have to exist on disk at the time of assignment.
1551 @raise ValueError: If the value is not an absolute path.
1552 @raise ValueError: If the value cannot be encoded properly.
1553 """
1554 if value is not None:
1555 if not os.path.isabs(value):
1556 raise ValueError("Not an absolute path: [%s]" % value)
1557 self._absolutePath = encodePath(value)
1558
1560 """
1561 Property target used to get the absolute path.
1562 """
1563 return self._absolutePath
1564
1566 """
1567 Property target used to set the collect mode.
1568 If not C{None}, the mode must be one of the values in L{VALID_COLLECT_MODES}.
1569 @raise ValueError: If the value is not valid.
1570 """
1571 if value is not None:
1572 if value not in VALID_COLLECT_MODES:
1573 raise ValueError("Collect mode must be one of %s." % VALID_COLLECT_MODES)
1574 self._collectMode = value
1575
1577 """
1578 Property target used to get the collect mode.
1579 """
1580 return self._collectMode
1581
1583 """
1584 Property target used to set the archive mode.
1585 If not C{None}, the mode must be one of the values in L{VALID_ARCHIVE_MODES}.
1586 @raise ValueError: If the value is not valid.
1587 """
1588 if value is not None:
1589 if value not in VALID_ARCHIVE_MODES:
1590 raise ValueError("Archive mode must be one of %s." % VALID_ARCHIVE_MODES)
1591 self._archiveMode = value
1592
1594 """
1595 Property target used to get the archive mode.
1596 """
1597 return self._archiveMode
1598
1600 """
1601 Property target used to set the ignore file.
1602 The value must be a non-empty string if it is not C{None}.
1603 @raise ValueError: If the value is an empty string.
1604 """
1605 if value is not None:
1606 if len(value) < 1:
1607 raise ValueError("The ignore file must be a non-empty string.")
1608 self._ignoreFile = value
1609
1611 """
1612 Property target used to get the ignore file.
1613 """
1614 return self._ignoreFile
1615
1617 """
1618 Property target used to set the link depth.
1619 The value must be an integer >= 0.
1620 @raise ValueError: If the value is not valid.
1621 """
1622 if value is None:
1623 self._linkDepth = None
1624 else:
1625 try:
1626 value = int(value)
1627 except TypeError:
1628 raise ValueError("Link depth value must be an integer >= 0.")
1629 if value < 0:
1630 raise ValueError("Link depth value must be an integer >= 0.")
1631 self._linkDepth = value
1632
1634 """
1635 Property target used to get the action linkDepth.
1636 """
1637 return self._linkDepth
1638
1640 """
1641 Property target used to set the dereference flag.
1642 No validations, but we normalize the value to C{True} or C{False}.
1643 """
1644 if value:
1645 self._dereference = True
1646 else:
1647 self._dereference = False
1648
1650 """
1651 Property target used to get the dereference flag.
1652 """
1653 return self._dereference
1654
1656 """
1657 Property target used to set the recursionLevel.
1658 The value must be an integer.
1659 @raise ValueError: If the value is not valid.
1660 """
1661 if value is None:
1662 self._recursionLevel = None
1663 else:
1664 try:
1665 value = int(value)
1666 except TypeError:
1667 raise ValueError("Recusion level value must be an integer.")
1668 self._recursionLevel = value
1669
1671 """
1672 Property target used to get the action recursionLevel.
1673 """
1674 return self._recursionLevel
1675
1677 """
1678 Property target used to set the absolute exclude paths list.
1679 Either the value must be C{None} or each element must be an absolute path.
1680 Elements do not have to exist on disk at the time of assignment.
1681 @raise ValueError: If the value is not an absolute path.
1682 """
1683 if value is None:
1684 self._absoluteExcludePaths = None
1685 else:
1686 try:
1687 saved = self._absoluteExcludePaths
1688 self._absoluteExcludePaths = AbsolutePathList()
1689 self._absoluteExcludePaths.extend(value)
1690 except Exception as e:
1691 self._absoluteExcludePaths = saved
1692 raise e
1693
1695 """
1696 Property target used to get the absolute exclude paths list.
1697 """
1698 return self._absoluteExcludePaths
1699
1701 """
1702 Property target used to set the relative exclude paths list.
1703 Elements do not have to exist on disk at the time of assignment.
1704 """
1705 if value is None:
1706 self._relativeExcludePaths = None
1707 else:
1708 try:
1709 saved = self._relativeExcludePaths
1710 self._relativeExcludePaths = UnorderedList()
1711 self._relativeExcludePaths.extend(value)
1712 except Exception as e:
1713 self._relativeExcludePaths = saved
1714 raise e
1715
1717 """
1718 Property target used to get the relative exclude paths list.
1719 """
1720 return self._relativeExcludePaths
1721
1723 """
1724 Property target used to set the exclude patterns list.
1725 """
1726 if value is None:
1727 self._excludePatterns = None
1728 else:
1729 try:
1730 saved = self._excludePatterns
1731 self._excludePatterns = RegexList()
1732 self._excludePatterns.extend(value)
1733 except Exception as e:
1734 self._excludePatterns = saved
1735 raise e
1736
1738 """
1739 Property target used to get the exclude patterns list.
1740 """
1741 return self._excludePatterns
1742
1743 absolutePath = property(_getAbsolutePath, _setAbsolutePath, None, doc="Absolute path of the directory to collect.")
1744 collectMode = property(_getCollectMode, _setCollectMode, None, doc="Overridden collect mode for this directory.")
1745 archiveMode = property(_getArchiveMode, _setArchiveMode, None, doc="Overridden archive mode for this directory.")
1746 ignoreFile = property(_getIgnoreFile, _setIgnoreFile, None, doc="Overridden ignore file name for this directory.")
1747 linkDepth = property(_getLinkDepth, _setLinkDepth, None, doc="Maximum at which soft links should be followed.")
1748 dereference = property(_getDereference, _setDereference, None, doc="Whether to dereference links that are followed.")
1749 recursionLevel = property(_getRecursionLevel, _setRecursionLevel, None, "Recursion level to use for recursive directory collection")
1750 absoluteExcludePaths = property(_getAbsoluteExcludePaths, _setAbsoluteExcludePaths, None, "List of absolute paths to exclude.")
1751 relativeExcludePaths = property(_getRelativeExcludePaths, _setRelativeExcludePaths, None, "List of relative paths to exclude.")
1752 excludePatterns = property(_getExcludePatterns, _setExcludePatterns, None, "List of regular expression patterns to exclude.")
1753
1754
1755
1756
1757
1758
1759 @total_ordering
1760 -class PurgeDir(object):
1761
1762 """
1763 Class representing a Cedar Backup purge directory.
1764
1765 The following restrictions exist on data in this class:
1766
1767 - The absolute path must be an absolute path
1768 - The retain days value must be an integer >= 0.
1769
1770 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__, absolutePath, retainDays
1771 """
1772
1773 - def __init__(self, absolutePath=None, retainDays=None):
1774 """
1775 Constructor for the C{PurgeDir} class.
1776
1777 @param absolutePath: Absolute path of the directory to be purged.
1778 @param retainDays: Number of days content within directory should be retained.
1779
1780 @raise ValueError: If one of the values is invalid.
1781 """
1782 self._absolutePath = None
1783 self._retainDays = None
1784 self.absolutePath = absolutePath
1785 self.retainDays = retainDays
1786
1788 """
1789 Official string representation for class instance.
1790 """
1791 return "PurgeDir(%s, %s)" % (self.absolutePath, self.retainDays)
1792
1794 """
1795 Informal string representation for class instance.
1796 """
1797 return self.__repr__()
1798
1800 """Equals operator, iplemented in terms of original Python 2 compare operator."""
1801 return self.__cmp__(other) == 0
1802
1804 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
1805 return self.__cmp__(other) < 0
1806
1808 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
1809 return self.__cmp__(other) > 0
1810
1812 """
1813 Original Python 2 comparison operator.
1814 @param other: Other object to compare to.
1815 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other.
1816 """
1817 if other is None:
1818 return 1
1819 if self.absolutePath != other.absolutePath:
1820 if str(self.absolutePath or "") < str(other.absolutePath or ""):
1821 return -1
1822 else:
1823 return 1
1824 if self.retainDays != other.retainDays:
1825 if int(self.retainDays or 0) < int(other.retainDays or 0):
1826 return -1
1827 else:
1828 return 1
1829 return 0
1830
1832 """
1833 Property target used to set the absolute path.
1834 The value must be an absolute path if it is not C{None}.
1835 It does not have to exist on disk at the time of assignment.
1836 @raise ValueError: If the value is not an absolute path.
1837 @raise ValueError: If the value cannot be encoded properly.
1838 """
1839 if value is not None:
1840 if not os.path.isabs(value):
1841 raise ValueError("Absolute path must, er, be an absolute path.")
1842 self._absolutePath = encodePath(value)
1843
1845 """
1846 Property target used to get the absolute path.
1847 """
1848 return self._absolutePath
1849
1851 """
1852 Property target used to set the retain days value.
1853 The value must be an integer >= 0.
1854 @raise ValueError: If the value is not valid.
1855 """
1856 if value is None:
1857 self._retainDays = None
1858 else:
1859 try:
1860 value = int(value)
1861 except TypeError:
1862 raise ValueError("Retain days value must be an integer >= 0.")
1863 if value < 0:
1864 raise ValueError("Retain days value must be an integer >= 0.")
1865 self._retainDays = value
1866
1868 """
1869 Property target used to get the absolute path.
1870 """
1871 return self._retainDays
1872
1873 absolutePath = property(_getAbsolutePath, _setAbsolutePath, None, "Absolute path of directory to purge.")
1874 retainDays = property(_getRetainDays, _setRetainDays, None, "Number of days content within directory should be retained.")
1875
1876
1877
1878
1879
1880
1881 @total_ordering
1882 -class LocalPeer(object):
1883
1884 """
1885 Class representing a Cedar Backup peer.
1886
1887 The following restrictions exist on data in this class:
1888
1889 - The peer name must be a non-empty string.
1890 - The collect directory must be an absolute path.
1891 - The ignore failure mode must be one of the values in L{VALID_FAILURE_MODES}.
1892
1893 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__, name, collectDir
1894 """
1895
1896 - def __init__(self, name=None, collectDir=None, ignoreFailureMode=None):
1897 """
1898 Constructor for the C{LocalPeer} class.
1899
1900 @param name: Name of the peer, typically a valid hostname.
1901 @param collectDir: Collect directory to stage files from on peer.
1902 @param ignoreFailureMode: Ignore failure mode for peer.
1903
1904 @raise ValueError: If one of the values is invalid.
1905 """
1906 self._name = None
1907 self._collectDir = None
1908 self._ignoreFailureMode = None
1909 self.name = name
1910 self.collectDir = collectDir
1911 self.ignoreFailureMode = ignoreFailureMode
1912
1914 """
1915 Official string representation for class instance.
1916 """
1917 return "LocalPeer(%s, %s, %s)" % (self.name, self.collectDir, self.ignoreFailureMode)
1918
1920 """
1921 Informal string representation for class instance.
1922 """
1923 return self.__repr__()
1924
1926 """Equals operator, iplemented in terms of original Python 2 compare operator."""
1927 return self.__cmp__(other) == 0
1928
1930 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
1931 return self.__cmp__(other) < 0
1932
1934 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
1935 return self.__cmp__(other) > 0
1936
1938 """
1939 Original Python 2 comparison operator.
1940 @param other: Other object to compare to.
1941 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other.
1942 """
1943 if other is None:
1944 return 1
1945 if self.name != other.name:
1946 if str(self.name or "") < str(other.name or ""):
1947 return -1
1948 else:
1949 return 1
1950 if self.collectDir != other.collectDir:
1951 if str(self.collectDir or "") < str(other.collectDir or ""):
1952 return -1
1953 else:
1954 return 1
1955 if self.ignoreFailureMode != other.ignoreFailureMode:
1956 if str(self.ignoreFailureMode or "") < str(other.ignoreFailureMode or ""):
1957 return -1
1958 else:
1959 return 1
1960 return 0
1961
1963 """
1964 Property target used to set the peer name.
1965 The value must be a non-empty string if it is not C{None}.
1966 @raise ValueError: If the value is an empty string.
1967 """
1968 if value is not None:
1969 if len(value) < 1:
1970 raise ValueError("The peer name must be a non-empty string.")
1971 self._name = value
1972
1974 """
1975 Property target used to get the peer name.
1976 """
1977 return self._name
1978
1980 """
1981 Property target used to set the collect directory.
1982 The value must be an absolute path if it is not C{None}.
1983 It does not have to exist on disk at the time of assignment.
1984 @raise ValueError: If the value is not an absolute path.
1985 @raise ValueError: If the value cannot be encoded properly.
1986 """
1987 if value is not None:
1988 if not os.path.isabs(value):
1989 raise ValueError("Collect directory must be an absolute path.")
1990 self._collectDir = encodePath(value)
1991
1993 """
1994 Property target used to get the collect directory.
1995 """
1996 return self._collectDir
1997
1999 """
2000 Property target used to set the ignoreFailure mode.
2001 If not C{None}, the mode must be one of the values in L{VALID_FAILURE_MODES}.
2002 @raise ValueError: If the value is not valid.
2003 """
2004 if value is not None:
2005 if value not in VALID_FAILURE_MODES:
2006 raise ValueError("Ignore failure mode must be one of %s." % VALID_FAILURE_MODES)
2007 self._ignoreFailureMode = value
2008
2010 """
2011 Property target used to get the ignoreFailure mode.
2012 """
2013 return self._ignoreFailureMode
2014
2015 name = property(_getName, _setName, None, "Name of the peer, typically a valid hostname.")
2016 collectDir = property(_getCollectDir, _setCollectDir, None, "Collect directory to stage files from on peer.")
2017 ignoreFailureMode = property(_getIgnoreFailureMode, _setIgnoreFailureMode, None, "Ignore failure mode for peer.")
2018
2019
2020
2021
2022
2023
2024 @total_ordering
2025 -class RemotePeer(object):
2026
2027 """
2028 Class representing a Cedar Backup peer.
2029
2030 The following restrictions exist on data in this class:
2031
2032 - The peer name must be a non-empty string.
2033 - The collect directory must be an absolute path.
2034 - The remote user must be a non-empty string.
2035 - The rcp command must be a non-empty string.
2036 - The rsh command must be a non-empty string.
2037 - The cback command must be a non-empty string.
2038 - Any managed action name must be a non-empty string matching C{ACTION_NAME_REGEX}
2039 - The ignore failure mode must be one of the values in L{VALID_FAILURE_MODES}.
2040
2041 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__, name, collectDir, remoteUser, rcpCommand
2042 """
2043
2044 - def __init__(self, name=None, collectDir=None, remoteUser=None,
2045 rcpCommand=None, rshCommand=None, cbackCommand=None,
2046 managed=False, managedActions=None, ignoreFailureMode=None):
2047 """
2048 Constructor for the C{RemotePeer} class.
2049
2050 @param name: Name of the peer, must be a valid hostname.
2051 @param collectDir: Collect directory to stage files from on peer.
2052 @param remoteUser: Name of backup user on remote peer.
2053 @param rcpCommand: Overridden rcp-compatible copy command for peer.
2054 @param rshCommand: Overridden rsh-compatible remote shell command for peer.
2055 @param cbackCommand: Overridden cback-compatible command to use on remote peer.
2056 @param managed: Indicates whether this is a managed peer.
2057 @param managedActions: Overridden set of actions that are managed on the peer.
2058 @param ignoreFailureMode: Ignore failure mode for peer.
2059
2060 @raise ValueError: If one of the values is invalid.
2061 """
2062 self._name = None
2063 self._collectDir = None
2064 self._remoteUser = None
2065 self._rcpCommand = None
2066 self._rshCommand = None
2067 self._cbackCommand = None
2068 self._managed = None
2069 self._managedActions = None
2070 self._ignoreFailureMode = None
2071 self.name = name
2072 self.collectDir = collectDir
2073 self.remoteUser = remoteUser
2074 self.rcpCommand = rcpCommand
2075 self.rshCommand = rshCommand
2076 self.cbackCommand = cbackCommand
2077 self.managed = managed
2078 self.managedActions = managedActions
2079 self.ignoreFailureMode = ignoreFailureMode
2080
2082 """
2083 Official string representation for class instance.
2084 """
2085 return "RemotePeer(%s, %s, %s, %s, %s, %s, %s, %s, %s)" % (self.name, self.collectDir, self.remoteUser,
2086 self.rcpCommand, self.rshCommand, self.cbackCommand,
2087 self.managed, self.managedActions, self.ignoreFailureMode)
2088
2090 """
2091 Informal string representation for class instance.
2092 """
2093 return self.__repr__()
2094
2096 """Equals operator, iplemented in terms of original Python 2 compare operator."""
2097 return self.__cmp__(other) == 0
2098
2100 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
2101 return self.__cmp__(other) < 0
2102
2104 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
2105 return self.__cmp__(other) > 0
2106
2161
2163 """
2164 Property target used to set the peer name.
2165 The value must be a non-empty string if it is not C{None}.
2166 @raise ValueError: If the value is an empty string.
2167 """
2168 if value is not None:
2169 if len(value) < 1:
2170 raise ValueError("The peer name must be a non-empty string.")
2171 self._name = value
2172
2174 """
2175 Property target used to get the peer name.
2176 """
2177 return self._name
2178
2180 """
2181 Property target used to set the collect directory.
2182 The value must be an absolute path if it is not C{None}.
2183 It does not have to exist on disk at the time of assignment.
2184 @raise ValueError: If the value is not an absolute path.
2185 @raise ValueError: If the value cannot be encoded properly.
2186 """
2187 if value is not None:
2188 if not os.path.isabs(value):
2189 raise ValueError("Collect directory must be an absolute path.")
2190 self._collectDir = encodePath(value)
2191
2193 """
2194 Property target used to get the collect directory.
2195 """
2196 return self._collectDir
2197
2199 """
2200 Property target used to set the remote user.
2201 The value must be a non-empty string if it is not C{None}.
2202 @raise ValueError: If the value is an empty string.
2203 """
2204 if value is not None:
2205 if len(value) < 1:
2206 raise ValueError("The remote user must be a non-empty string.")
2207 self._remoteUser = value
2208
2210 """
2211 Property target used to get the remote user.
2212 """
2213 return self._remoteUser
2214
2216 """
2217 Property target used to set the rcp command.
2218 The value must be a non-empty string if it is not C{None}.
2219 @raise ValueError: If the value is an empty string.
2220 """
2221 if value is not None:
2222 if len(value) < 1:
2223 raise ValueError("The rcp command must be a non-empty string.")
2224 self._rcpCommand = value
2225
2227 """
2228 Property target used to get the rcp command.
2229 """
2230 return self._rcpCommand
2231
2233 """
2234 Property target used to set the rsh command.
2235 The value must be a non-empty string if it is not C{None}.
2236 @raise ValueError: If the value is an empty string.
2237 """
2238 if value is not None:
2239 if len(value) < 1:
2240 raise ValueError("The rsh command must be a non-empty string.")
2241 self._rshCommand = value
2242
2244 """
2245 Property target used to get the rsh command.
2246 """
2247 return self._rshCommand
2248
2250 """
2251 Property target used to set the cback command.
2252 The value must be a non-empty string if it is not C{None}.
2253 @raise ValueError: If the value is an empty string.
2254 """
2255 if value is not None:
2256 if len(value) < 1:
2257 raise ValueError("The cback command must be a non-empty string.")
2258 self._cbackCommand = value
2259
2261 """
2262 Property target used to get the cback command.
2263 """
2264 return self._cbackCommand
2265
2267 """
2268 Property target used to set the managed flag.
2269 No validations, but we normalize the value to C{True} or C{False}.
2270 """
2271 if value:
2272 self._managed = True
2273 else:
2274 self._managed = False
2275
2277 """
2278 Property target used to get the managed flag.
2279 """
2280 return self._managed
2281
2283 """
2284 Property target used to set the managed actions list.
2285 Elements do not have to exist on disk at the time of assignment.
2286 """
2287 if value is None:
2288 self._managedActions = None
2289 else:
2290 try:
2291 saved = self._managedActions
2292 self._managedActions = RegexMatchList(ACTION_NAME_REGEX, emptyAllowed=False, prefix="Action name")
2293 self._managedActions.extend(value)
2294 except Exception as e:
2295 self._managedActions = saved
2296 raise e
2297
2299 """
2300 Property target used to get the managed actions list.
2301 """
2302 return self._managedActions
2303
2305 """
2306 Property target used to set the ignoreFailure mode.
2307 If not C{None}, the mode must be one of the values in L{VALID_FAILURE_MODES}.
2308 @raise ValueError: If the value is not valid.
2309 """
2310 if value is not None:
2311 if value not in VALID_FAILURE_MODES:
2312 raise ValueError("Ignore failure mode must be one of %s." % VALID_FAILURE_MODES)
2313 self._ignoreFailureMode = value
2314
2316 """
2317 Property target used to get the ignoreFailure mode.
2318 """
2319 return self._ignoreFailureMode
2320
2321 name = property(_getName, _setName, None, "Name of the peer, must be a valid hostname.")
2322 collectDir = property(_getCollectDir, _setCollectDir, None, "Collect directory to stage files from on peer.")
2323 remoteUser = property(_getRemoteUser, _setRemoteUser, None, "Name of backup user on remote peer.")
2324 rcpCommand = property(_getRcpCommand, _setRcpCommand, None, "Overridden rcp-compatible copy command for peer.")
2325 rshCommand = property(_getRshCommand, _setRshCommand, None, "Overridden rsh-compatible remote shell command for peer.")
2326 cbackCommand = property(_getCbackCommand, _setCbackCommand, None, "Overridden cback-compatible command to use on remote peer.")
2327 managed = property(_getManaged, _setManaged, None, "Indicates whether this is a managed peer.")
2328 managedActions = property(_getManagedActions, _setManagedActions, None, "Overridden set of actions that are managed on the peer.")
2329 ignoreFailureMode = property(_getIgnoreFailureMode, _setIgnoreFailureMode, None, "Ignore failure mode for peer.")
2330
2331
2332
2333
2334
2335
2336 @total_ordering
2337 -class ReferenceConfig(object):
2338
2339 """
2340 Class representing a Cedar Backup reference configuration.
2341
2342 The reference information is just used for saving off metadata about
2343 configuration and exists mostly for backwards-compatibility with Cedar
2344 Backup 1.x.
2345
2346 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__, author, revision, description, generator
2347 """
2348
2349 - def __init__(self, author=None, revision=None, description=None, generator=None):
2350 """
2351 Constructor for the C{ReferenceConfig} class.
2352
2353 @param author: Author of the configuration file.
2354 @param revision: Revision of the configuration file.
2355 @param description: Description of the configuration file.
2356 @param generator: Tool that generated the configuration file.
2357 """
2358 self._author = None
2359 self._revision = None
2360 self._description = None
2361 self._generator = None
2362 self.author = author
2363 self.revision = revision
2364 self.description = description
2365 self.generator = generator
2366
2368 """
2369 Official string representation for class instance.
2370 """
2371 return "ReferenceConfig(%s, %s, %s, %s)" % (self.author, self.revision, self.description, self.generator)
2372
2374 """
2375 Informal string representation for class instance.
2376 """
2377 return self.__repr__()
2378
2380 """Equals operator, iplemented in terms of original Python 2 compare operator."""
2381 return self.__cmp__(other) == 0
2382
2384 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
2385 return self.__cmp__(other) < 0
2386
2388 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
2389 return self.__cmp__(other) > 0
2390
2392 """
2393 Original Python 2 comparison operator.
2394 @param other: Other object to compare to.
2395 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other.
2396 """
2397 if other is None:
2398 return 1
2399 if self.author != other.author:
2400 if str(self.author or "") < str(other.author or ""):
2401 return -1
2402 else:
2403 return 1
2404 if self.revision != other.revision:
2405 if str(self.revision or "") < str(other.revision or ""):
2406 return -1
2407 else:
2408 return 1
2409 if self.description != other.description:
2410 if str(self.description or "") < str(other.description or ""):
2411 return -1
2412 else:
2413 return 1
2414 if self.generator != other.generator:
2415 if str(self.generator or "") < str(other.generator or ""):
2416 return -1
2417 else:
2418 return 1
2419 return 0
2420
2422 """
2423 Property target used to set the author value.
2424 No validations.
2425 """
2426 self._author = value
2427
2429 """
2430 Property target used to get the author value.
2431 """
2432 return self._author
2433
2435 """
2436 Property target used to set the revision value.
2437 No validations.
2438 """
2439 self._revision = value
2440
2442 """
2443 Property target used to get the revision value.
2444 """
2445 return self._revision
2446
2448 """
2449 Property target used to set the description value.
2450 No validations.
2451 """
2452 self._description = value
2453
2455 """
2456 Property target used to get the description value.
2457 """
2458 return self._description
2459
2461 """
2462 Property target used to set the generator value.
2463 No validations.
2464 """
2465 self._generator = value
2466
2468 """
2469 Property target used to get the generator value.
2470 """
2471 return self._generator
2472
2473 author = property(_getAuthor, _setAuthor, None, "Author of the configuration file.")
2474 revision = property(_getRevision, _setRevision, None, "Revision of the configuration file.")
2475 description = property(_getDescription, _setDescription, None, "Description of the configuration file.")
2476 generator = property(_getGenerator, _setGenerator, None, "Tool that generated the configuration file.")
2477
2485
2486 """
2487 Class representing Cedar Backup extensions configuration.
2488
2489 Extensions configuration is used to specify "extended actions" implemented
2490 by code external to Cedar Backup. For instance, a hypothetical third party
2491 might write extension code to collect database repository data. If they
2492 write a properly-formatted extension function, they can use the extension
2493 configuration to map a command-line Cedar Backup action (i.e. "database")
2494 to their function.
2495
2496 The following restrictions exist on data in this class:
2497
2498 - If set, the order mode must be one of the values in C{VALID_ORDER_MODES}
2499 - The actions list must be a list of C{ExtendedAction} objects.
2500
2501 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__, orderMode, actions
2502 """
2503
2504 - def __init__(self, actions=None, orderMode=None):
2505 """
2506 Constructor for the C{ExtensionsConfig} class.
2507 @param actions: List of extended actions
2508 """
2509 self._orderMode = None
2510 self._actions = None
2511 self.orderMode = orderMode
2512 self.actions = actions
2513
2515 """
2516 Official string representation for class instance.
2517 """
2518 return "ExtensionsConfig(%s, %s)" % (self.orderMode, self.actions)
2519
2521 """
2522 Informal string representation for class instance.
2523 """
2524 return self.__repr__()
2525
2527 """Equals operator, iplemented in terms of original Python 2 compare operator."""
2528 return self.__cmp__(other) == 0
2529
2531 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
2532 return self.__cmp__(other) < 0
2533
2535 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
2536 return self.__cmp__(other) > 0
2537
2539 """
2540 Original Python 2 comparison operator.
2541 @param other: Other object to compare to.
2542 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other.
2543 """
2544 if other is None:
2545 return 1
2546 if self.orderMode != other.orderMode:
2547 if str(self.orderMode or "") < str(other.orderMode or ""):
2548 return -1
2549 else:
2550 return 1
2551 if self.actions != other.actions:
2552 if self.actions < other.actions:
2553 return -1
2554 else:
2555 return 1
2556 return 0
2557
2559 """
2560 Property target used to set the order mode.
2561 The value must be one of L{VALID_ORDER_MODES}.
2562 @raise ValueError: If the value is not valid.
2563 """
2564 if value is not None:
2565 if value not in VALID_ORDER_MODES:
2566 raise ValueError("Order mode must be one of %s." % VALID_ORDER_MODES)
2567 self._orderMode = value
2568
2570 """
2571 Property target used to get the order mode.
2572 """
2573 return self._orderMode
2574
2576 """
2577 Property target used to set the actions list.
2578 Either the value must be C{None} or each element must be an C{ExtendedAction}.
2579 @raise ValueError: If the value is not a C{ExtendedAction}
2580 """
2581 if value is None:
2582 self._actions = None
2583 else:
2584 try:
2585 saved = self._actions
2586 self._actions = ObjectTypeList(ExtendedAction, "ExtendedAction")
2587 self._actions.extend(value)
2588 except Exception as e:
2589 self._actions = saved
2590 raise e
2591
2593 """
2594 Property target used to get the actions list.
2595 """
2596 return self._actions
2597
2598 orderMode = property(_getOrderMode, _setOrderMode, None, "Order mode for extensions, to control execution ordering.")
2599 actions = property(_getActions, _setActions, None, "List of extended actions.")
2600
2601
2602
2603
2604
2605
2606 @total_ordering
2607 -class OptionsConfig(object):
2608
2609 """
2610 Class representing a Cedar Backup global options configuration.
2611
2612 The options section is used to store global configuration options and
2613 defaults that can be applied to other sections.
2614
2615 The following restrictions exist on data in this class:
2616
2617 - The working directory must be an absolute path.
2618 - The starting day must be a day of the week in English, i.e. C{"monday"}, C{"tuesday"}, etc.
2619 - All of the other values must be non-empty strings if they are set to something other than C{None}.
2620 - The overrides list must be a list of C{CommandOverride} objects.
2621 - The hooks list must be a list of C{ActionHook} objects.
2622 - The cback command must be a non-empty string.
2623 - Any managed action name must be a non-empty string matching C{ACTION_NAME_REGEX}
2624
2625 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__, startingDay, workingDir,
2626 backupUser, backupGroup, rcpCommand, rshCommand, overrides
2627 """
2628
2629 - def __init__(self, startingDay=None, workingDir=None, backupUser=None,
2630 backupGroup=None, rcpCommand=None, overrides=None,
2631 hooks=None, rshCommand=None, cbackCommand=None,
2632 managedActions=None):
2633 """
2634 Constructor for the C{OptionsConfig} class.
2635
2636 @param startingDay: Day that starts the week.
2637 @param workingDir: Working (temporary) directory to use for backups.
2638 @param backupUser: Effective user that backups should run as.
2639 @param backupGroup: Effective group that backups should run as.
2640 @param rcpCommand: Default rcp-compatible copy command for staging.
2641 @param rshCommand: Default rsh-compatible command to use for remote shells.
2642 @param cbackCommand: Default cback-compatible command to use on managed remote peers.
2643 @param overrides: List of configured command path overrides, if any.
2644 @param hooks: List of configured pre- and post-action hooks.
2645 @param managedActions: Default set of actions that are managed on remote peers.
2646
2647 @raise ValueError: If one of the values is invalid.
2648 """
2649 self._startingDay = None
2650 self._workingDir = None
2651 self._backupUser = None
2652 self._backupGroup = None
2653 self._rcpCommand = None
2654 self._rshCommand = None
2655 self._cbackCommand = None
2656 self._overrides = None
2657 self._hooks = None
2658 self._managedActions = None
2659 self.startingDay = startingDay
2660 self.workingDir = workingDir
2661 self.backupUser = backupUser
2662 self.backupGroup = backupGroup
2663 self.rcpCommand = rcpCommand
2664 self.rshCommand = rshCommand
2665 self.cbackCommand = cbackCommand
2666 self.overrides = overrides
2667 self.hooks = hooks
2668 self.managedActions = managedActions
2669
2671 """
2672 Official string representation for class instance.
2673 """
2674 return "OptionsConfig(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" % (self.startingDay, self.workingDir,
2675 self.backupUser, self.backupGroup,
2676 self.rcpCommand, self.overrides,
2677 self.hooks, self.rshCommand,
2678 self.cbackCommand, self.managedActions)
2679
2681 """
2682 Informal string representation for class instance.
2683 """
2684 return self.__repr__()
2685
2687 """Equals operator, iplemented in terms of original Python 2 compare operator."""
2688 return self.__cmp__(other) == 0
2689
2691 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
2692 return self.__cmp__(other) < 0
2693
2695 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
2696 return self.__cmp__(other) > 0
2697
2757
2759 """
2760 If no override currently exists for the command, add one.
2761 @param command: Name of command to be overridden.
2762 @param absolutePath: Absolute path of the overrridden command.
2763 """
2764 override = CommandOverride(command, absolutePath)
2765 if self.overrides is None:
2766 self.overrides = [ override, ]
2767 else:
2768 exists = False
2769 for obj in self.overrides:
2770 if obj.command == override.command:
2771 exists = True
2772 break
2773 if not exists:
2774 self.overrides.append(override)
2775
2777 """
2778 If override currently exists for the command, replace it; otherwise add it.
2779 @param command: Name of command to be overridden.
2780 @param absolutePath: Absolute path of the overrridden command.
2781 """
2782 override = CommandOverride(command, absolutePath)
2783 if self.overrides is None:
2784 self.overrides = [ override, ]
2785 else:
2786 exists = False
2787 for obj in self.overrides:
2788 if obj.command == override.command:
2789 exists = True
2790 obj.absolutePath = override.absolutePath
2791 break
2792 if not exists:
2793 self.overrides.append(override)
2794
2796 """
2797 Property target used to set the starting day.
2798 If it is not C{None}, the value must be a valid English day of the week,
2799 one of C{"monday"}, C{"tuesday"}, C{"wednesday"}, etc.
2800 @raise ValueError: If the value is not a valid day of the week.
2801 """
2802 if value is not None:
2803 if value not in ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday", ]:
2804 raise ValueError("Starting day must be an English day of the week, i.e. \"monday\".")
2805 self._startingDay = value
2806
2808 """
2809 Property target used to get the starting day.
2810 """
2811 return self._startingDay
2812
2814 """
2815 Property target used to set the working directory.
2816 The value must be an absolute path if it is not C{None}.
2817 It does not have to exist on disk at the time of assignment.
2818 @raise ValueError: If the value is not an absolute path.
2819 @raise ValueError: If the value cannot be encoded properly.
2820 """
2821 if value is not None:
2822 if not os.path.isabs(value):
2823 raise ValueError("Working directory must be an absolute path.")
2824 self._workingDir = encodePath(value)
2825
2827 """
2828 Property target used to get the working directory.
2829 """
2830 return self._workingDir
2831
2833 """
2834 Property target used to set the backup user.
2835 The value must be a non-empty string if it is not C{None}.
2836 @raise ValueError: If the value is an empty string.
2837 """
2838 if value is not None:
2839 if len(value) < 1:
2840 raise ValueError("Backup user must be a non-empty string.")
2841 self._backupUser = value
2842
2844 """
2845 Property target used to get the backup user.
2846 """
2847 return self._backupUser
2848
2850 """
2851 Property target used to set the backup group.
2852 The value must be a non-empty string if it is not C{None}.
2853 @raise ValueError: If the value is an empty string.
2854 """
2855 if value is not None:
2856 if len(value) < 1:
2857 raise ValueError("Backup group must be a non-empty string.")
2858 self._backupGroup = value
2859
2861 """
2862 Property target used to get the backup group.
2863 """
2864 return self._backupGroup
2865
2867 """
2868 Property target used to set the rcp command.
2869 The value must be a non-empty string if it is not C{None}.
2870 @raise ValueError: If the value is an empty string.
2871 """
2872 if value is not None:
2873 if len(value) < 1:
2874 raise ValueError("The rcp command must be a non-empty string.")
2875 self._rcpCommand = value
2876
2878 """
2879 Property target used to get the rcp command.
2880 """
2881 return self._rcpCommand
2882
2884 """
2885 Property target used to set the rsh command.
2886 The value must be a non-empty string if it is not C{None}.
2887 @raise ValueError: If the value is an empty string.
2888 """
2889 if value is not None:
2890 if len(value) < 1:
2891 raise ValueError("The rsh command must be a non-empty string.")
2892 self._rshCommand = value
2893
2895 """
2896 Property target used to get the rsh command.
2897 """
2898 return self._rshCommand
2899
2901 """
2902 Property target used to set the cback command.
2903 The value must be a non-empty string if it is not C{None}.
2904 @raise ValueError: If the value is an empty string.
2905 """
2906 if value is not None:
2907 if len(value) < 1:
2908 raise ValueError("The cback command must be a non-empty string.")
2909 self._cbackCommand = value
2910
2912 """
2913 Property target used to get the cback command.
2914 """
2915 return self._cbackCommand
2916
2918 """
2919 Property target used to set the command path overrides list.
2920 Either the value must be C{None} or each element must be a C{CommandOverride}.
2921 @raise ValueError: If the value is not a C{CommandOverride}
2922 """
2923 if value is None:
2924 self._overrides = None
2925 else:
2926 try:
2927 saved = self._overrides
2928 self._overrides = ObjectTypeList(CommandOverride, "CommandOverride")
2929 self._overrides.extend(value)
2930 except Exception as e:
2931 self._overrides = saved
2932 raise e
2933
2935 """
2936 Property target used to get the command path overrides list.
2937 """
2938 return self._overrides
2939
2941 """
2942 Property target used to set the pre- and post-action hooks list.
2943 Either the value must be C{None} or each element must be an C{ActionHook}.
2944 @raise ValueError: If the value is not a C{CommandOverride}
2945 """
2946 if value is None:
2947 self._hooks = None
2948 else:
2949 try:
2950 saved = self._hooks
2951 self._hooks = ObjectTypeList(ActionHook, "ActionHook")
2952 self._hooks.extend(value)
2953 except Exception as e:
2954 self._hooks = saved
2955 raise e
2956
2958 """
2959 Property target used to get the command path hooks list.
2960 """
2961 return self._hooks
2962
2964 """
2965 Property target used to set the managed actions list.
2966 Elements do not have to exist on disk at the time of assignment.
2967 """
2968 if value is None:
2969 self._managedActions = None
2970 else:
2971 try:
2972 saved = self._managedActions
2973 self._managedActions = RegexMatchList(ACTION_NAME_REGEX, emptyAllowed=False, prefix="Action name")
2974 self._managedActions.extend(value)
2975 except Exception as e:
2976 self._managedActions = saved
2977 raise e
2978
2980 """
2981 Property target used to get the managed actions list.
2982 """
2983 return self._managedActions
2984
2985 startingDay = property(_getStartingDay, _setStartingDay, None, "Day that starts the week.")
2986 workingDir = property(_getWorkingDir, _setWorkingDir, None, "Working (temporary) directory to use for backups.")
2987 backupUser = property(_getBackupUser, _setBackupUser, None, "Effective user that backups should run as.")
2988 backupGroup = property(_getBackupGroup, _setBackupGroup, None, "Effective group that backups should run as.")
2989 rcpCommand = property(_getRcpCommand, _setRcpCommand, None, "Default rcp-compatible copy command for staging.")
2990 rshCommand = property(_getRshCommand, _setRshCommand, None, "Default rsh-compatible command to use for remote shells.")
2991 cbackCommand = property(_getCbackCommand, _setCbackCommand, None, "Default cback-compatible command to use on managed remote peers.")
2992 overrides = property(_getOverrides, _setOverrides, None, "List of configured command path overrides, if any.")
2993 hooks = property(_getHooks, _setHooks, None, "List of configured pre- and post-action hooks.")
2994 managedActions = property(_getManagedActions, _setManagedActions, None, "Default set of actions that are managed on remote peers.")
2995
2996
2997
2998
2999
3000
3001 @total_ordering
3002 -class PeersConfig(object):
3003
3004 """
3005 Class representing Cedar Backup global peer configuration.
3006
3007 This section contains a list of local and remote peers in a master's backup
3008 pool. The section is optional. If a master does not define this section,
3009 then all peers are unmanaged, and the stage configuration section must
3010 explicitly list any peer that is to be staged. If this section is
3011 configured, then peers may be managed or unmanaged, and the stage section
3012 peer configuration (if any) completely overrides this configuration.
3013
3014 The following restrictions exist on data in this class:
3015
3016 - The list of local peers must contain only C{LocalPeer} objects
3017 - The list of remote peers must contain only C{RemotePeer} objects
3018
3019 @note: Lists within this class are "unordered" for equality comparisons.
3020
3021 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__, localPeers, remotePeers
3022 """
3023
3024 - def __init__(self, localPeers=None, remotePeers=None):
3025 """
3026 Constructor for the C{PeersConfig} class.
3027
3028 @param localPeers: List of local peers.
3029 @param remotePeers: List of remote peers.
3030
3031 @raise ValueError: If one of the values is invalid.
3032 """
3033 self._localPeers = None
3034 self._remotePeers = None
3035 self.localPeers = localPeers
3036 self.remotePeers = remotePeers
3037
3039 """
3040 Official string representation for class instance.
3041 """
3042 return "PeersConfig(%s, %s)" % (self.localPeers, self.remotePeers)
3043
3045 """
3046 Informal string representation for class instance.
3047 """
3048 return self.__repr__()
3049
3051 """Equals operator, iplemented in terms of original Python 2 compare operator."""
3052 return self.__cmp__(other) == 0
3053
3055 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
3056 return self.__cmp__(other) < 0
3057
3059 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
3060 return self.__cmp__(other) > 0
3061
3063 """
3064 Original Python 2 comparison operator.
3065 Lists within this class are "unordered" for equality comparisons.
3066 @param other: Other object to compare to.
3067 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other.
3068 """
3069 if other is None:
3070 return 1
3071 if self.localPeers != other.localPeers:
3072 if self.localPeers < other.localPeers:
3073 return -1
3074 else:
3075 return 1
3076 if self.remotePeers != other.remotePeers:
3077 if self.remotePeers < other.remotePeers:
3078 return -1
3079 else:
3080 return 1
3081 return 0
3082
3084 """
3085 Indicates whether any peers are filled into this object.
3086 @return: Boolean true if any local or remote peers are filled in, false otherwise.
3087 """
3088 return ((self.localPeers is not None and len(self.localPeers) > 0) or
3089 (self.remotePeers is not None and len(self.remotePeers) > 0))
3090
3092 """
3093 Property target used to set the local peers list.
3094 Either the value must be C{None} or each element must be a C{LocalPeer}.
3095 @raise ValueError: If the value is not an absolute path.
3096 """
3097 if value is None:
3098 self._localPeers = None
3099 else:
3100 try:
3101 saved = self._localPeers
3102 self._localPeers = ObjectTypeList(LocalPeer, "LocalPeer")
3103 self._localPeers.extend(value)
3104 except Exception as e:
3105 self._localPeers = saved
3106 raise e
3107
3109 """
3110 Property target used to get the local peers list.
3111 """
3112 return self._localPeers
3113
3115 """
3116 Property target used to set the remote peers list.
3117 Either the value must be C{None} or each element must be a C{RemotePeer}.
3118 @raise ValueError: If the value is not a C{RemotePeer}
3119 """
3120 if value is None:
3121 self._remotePeers = None
3122 else:
3123 try:
3124 saved = self._remotePeers
3125 self._remotePeers = ObjectTypeList(RemotePeer, "RemotePeer")
3126 self._remotePeers.extend(value)
3127 except Exception as e:
3128 self._remotePeers = saved
3129 raise e
3130
3132 """
3133 Property target used to get the remote peers list.
3134 """
3135 return self._remotePeers
3136
3137 localPeers = property(_getLocalPeers, _setLocalPeers, None, "List of local peers.")
3138 remotePeers = property(_getRemotePeers, _setRemotePeers, None, "List of remote peers.")
3139
3140
3141
3142
3143
3144
3145 @total_ordering
3146 -class CollectConfig(object):
3147
3148 """
3149 Class representing a Cedar Backup collect configuration.
3150
3151 The following restrictions exist on data in this class:
3152
3153 - The target directory must be an absolute path.
3154 - The collect mode must be one of the values in L{VALID_COLLECT_MODES}.
3155 - The archive mode must be one of the values in L{VALID_ARCHIVE_MODES}.
3156 - The ignore file must be a non-empty string.
3157 - Each of the paths in C{absoluteExcludePaths} must be an absolute path
3158 - The collect file list must be a list of C{CollectFile} objects.
3159 - The collect directory list must be a list of C{CollectDir} objects.
3160
3161 For the C{absoluteExcludePaths} list, validation is accomplished through the
3162 L{util.AbsolutePathList} list implementation that overrides common list
3163 methods and transparently does the absolute path validation for us.
3164
3165 For the C{collectFiles} and C{collectDirs} list, validation is accomplished
3166 through the L{util.ObjectTypeList} list implementation that overrides common
3167 list methods and transparently ensures that each element has an appropriate
3168 type.
3169
3170 @note: Lists within this class are "unordered" for equality comparisons.
3171
3172 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__, targetDir,
3173 collectMode, archiveMode, ignoreFile, absoluteExcludePaths,
3174 excludePatterns, collectFiles, collectDirs
3175 """
3176
3177 - def __init__(self, targetDir=None, collectMode=None, archiveMode=None, ignoreFile=None,
3178 absoluteExcludePaths=None, excludePatterns=None, collectFiles=None,
3179 collectDirs=None):
3180 """
3181 Constructor for the C{CollectConfig} class.
3182
3183 @param targetDir: Directory to collect files into.
3184 @param collectMode: Default collect mode.
3185 @param archiveMode: Default archive mode for collect files.
3186 @param ignoreFile: Default ignore file name.
3187 @param absoluteExcludePaths: List of absolute paths to exclude.
3188 @param excludePatterns: List of regular expression patterns to exclude.
3189 @param collectFiles: List of collect files.
3190 @param collectDirs: List of collect directories.
3191
3192 @raise ValueError: If one of the values is invalid.
3193 """
3194 self._targetDir = None
3195 self._collectMode = None
3196 self._archiveMode = None
3197 self._ignoreFile = None
3198 self._absoluteExcludePaths = None
3199 self._excludePatterns = None
3200 self._collectFiles = None
3201 self._collectDirs = None
3202 self.targetDir = targetDir
3203 self.collectMode = collectMode
3204 self.archiveMode = archiveMode
3205 self.ignoreFile = ignoreFile
3206 self.absoluteExcludePaths = absoluteExcludePaths
3207 self.excludePatterns = excludePatterns
3208 self.collectFiles = collectFiles
3209 self.collectDirs = collectDirs
3210
3212 """
3213 Official string representation for class instance.
3214 """
3215 return "CollectConfig(%s, %s, %s, %s, %s, %s, %s, %s)" % (self.targetDir, self.collectMode, self.archiveMode,
3216 self.ignoreFile, self.absoluteExcludePaths,
3217 self.excludePatterns, self.collectFiles, self.collectDirs)
3218
3220 """
3221 Informal string representation for class instance.
3222 """
3223 return self.__repr__()
3224
3226 """Equals operator, iplemented in terms of original Python 2 compare operator."""
3227 return self.__cmp__(other) == 0
3228
3230 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
3231 return self.__cmp__(other) < 0
3232
3234 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
3235 return self.__cmp__(other) > 0
3236
3287
3289 """
3290 Property target used to set the target directory.
3291 The value must be an absolute path if it is not C{None}.
3292 It does not have to exist on disk at the time of assignment.
3293 @raise ValueError: If the value is not an absolute path.
3294 @raise ValueError: If the value cannot be encoded properly.
3295 """
3296 if value is not None:
3297 if not os.path.isabs(value):
3298 raise ValueError("Target directory must be an absolute path.")
3299 self._targetDir = encodePath(value)
3300
3302 """
3303 Property target used to get the target directory.
3304 """
3305 return self._targetDir
3306
3308 """
3309 Property target used to set the collect mode.
3310 If not C{None}, the mode must be one of L{VALID_COLLECT_MODES}.
3311 @raise ValueError: If the value is not valid.
3312 """
3313 if value is not None:
3314 if value not in VALID_COLLECT_MODES:
3315 raise ValueError("Collect mode must be one of %s." % VALID_COLLECT_MODES)
3316 self._collectMode = value
3317
3319 """
3320 Property target used to get the collect mode.
3321 """
3322 return self._collectMode
3323
3325 """
3326 Property target used to set the archive mode.
3327 If not C{None}, the mode must be one of L{VALID_ARCHIVE_MODES}.
3328 @raise ValueError: If the value is not valid.
3329 """
3330 if value is not None:
3331 if value not in VALID_ARCHIVE_MODES:
3332 raise ValueError("Archive mode must be one of %s." % VALID_ARCHIVE_MODES)
3333 self._archiveMode = value
3334
3336 """
3337 Property target used to get the archive mode.
3338 """
3339 return self._archiveMode
3340
3342 """
3343 Property target used to set the ignore file.
3344 The value must be a non-empty string if it is not C{None}.
3345 @raise ValueError: If the value is an empty string.
3346 @raise ValueError: If the value cannot be encoded properly.
3347 """
3348 if value is not None:
3349 if len(value) < 1:
3350 raise ValueError("The ignore file must be a non-empty string.")
3351 self._ignoreFile = encodePath(value)
3352
3354 """
3355 Property target used to get the ignore file.
3356 """
3357 return self._ignoreFile
3358
3360 """
3361 Property target used to set the absolute exclude paths list.
3362 Either the value must be C{None} or each element must be an absolute path.
3363 Elements do not have to exist on disk at the time of assignment.
3364 @raise ValueError: If the value is not an absolute path.
3365 """
3366 if value is None:
3367 self._absoluteExcludePaths = None
3368 else:
3369 try:
3370 saved = self._absoluteExcludePaths
3371 self._absoluteExcludePaths = AbsolutePathList()
3372 self._absoluteExcludePaths.extend(value)
3373 except Exception as e:
3374 self._absoluteExcludePaths = saved
3375 raise e
3376
3378 """
3379 Property target used to get the absolute exclude paths list.
3380 """
3381 return self._absoluteExcludePaths
3382
3384 """
3385 Property target used to set the exclude patterns list.
3386 """
3387 if value is None:
3388 self._excludePatterns = None
3389 else:
3390 try:
3391 saved = self._excludePatterns
3392 self._excludePatterns = RegexList()
3393 self._excludePatterns.extend(value)
3394 except Exception as e:
3395 self._excludePatterns = saved
3396 raise e
3397
3399 """
3400 Property target used to get the exclude patterns list.
3401 """
3402 return self._excludePatterns
3403
3405 """
3406 Property target used to set the collect files list.
3407 Either the value must be C{None} or each element must be a C{CollectFile}.
3408 @raise ValueError: If the value is not a C{CollectFile}
3409 """
3410 if value is None:
3411 self._collectFiles = None
3412 else:
3413 try:
3414 saved = self._collectFiles
3415 self._collectFiles = ObjectTypeList(CollectFile, "CollectFile")
3416 self._collectFiles.extend(value)
3417 except Exception as e:
3418 self._collectFiles = saved
3419 raise e
3420
3422 """
3423 Property target used to get the collect files list.
3424 """
3425 return self._collectFiles
3426
3428 """
3429 Property target used to set the collect dirs list.
3430 Either the value must be C{None} or each element must be a C{CollectDir}.
3431 @raise ValueError: If the value is not a C{CollectDir}
3432 """
3433 if value is None:
3434 self._collectDirs = None
3435 else:
3436 try:
3437 saved = self._collectDirs
3438 self._collectDirs = ObjectTypeList(CollectDir, "CollectDir")
3439 self._collectDirs.extend(value)
3440 except Exception as e:
3441 self._collectDirs = saved
3442 raise e
3443
3445 """
3446 Property target used to get the collect dirs list.
3447 """
3448 return self._collectDirs
3449
3450 targetDir = property(_getTargetDir, _setTargetDir, None, "Directory to collect files into.")
3451 collectMode = property(_getCollectMode, _setCollectMode, None, "Default collect mode.")
3452 archiveMode = property(_getArchiveMode, _setArchiveMode, None, "Default archive mode for collect files.")
3453 ignoreFile = property(_getIgnoreFile, _setIgnoreFile, None, "Default ignore file name.")
3454 absoluteExcludePaths = property(_getAbsoluteExcludePaths, _setAbsoluteExcludePaths, None, "List of absolute paths to exclude.")
3455 excludePatterns = property(_getExcludePatterns, _setExcludePatterns, None, "List of regular expressions patterns to exclude.")
3456 collectFiles = property(_getCollectFiles, _setCollectFiles, None, "List of collect files.")
3457 collectDirs = property(_getCollectDirs, _setCollectDirs, None, "List of collect directories.")
3458
3459
3460
3461
3462
3463
3464 @total_ordering
3465 -class StageConfig(object):
3466
3467 """
3468 Class representing a Cedar Backup stage configuration.
3469
3470 The following restrictions exist on data in this class:
3471
3472 - The target directory must be an absolute path
3473 - The list of local peers must contain only C{LocalPeer} objects
3474 - The list of remote peers must contain only C{RemotePeer} objects
3475
3476 @note: Lists within this class are "unordered" for equality comparisons.
3477
3478 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__, targetDir, localPeers, remotePeers
3479 """
3480
3481 - def __init__(self, targetDir=None, localPeers=None, remotePeers=None):
3482 """
3483 Constructor for the C{StageConfig} class.
3484
3485 @param targetDir: Directory to stage files into, by peer name.
3486 @param localPeers: List of local peers.
3487 @param remotePeers: List of remote peers.
3488
3489 @raise ValueError: If one of the values is invalid.
3490 """
3491 self._targetDir = None
3492 self._localPeers = None
3493 self._remotePeers = None
3494 self.targetDir = targetDir
3495 self.localPeers = localPeers
3496 self.remotePeers = remotePeers
3497
3499 """
3500 Official string representation for class instance.
3501 """
3502 return "StageConfig(%s, %s, %s)" % (self.targetDir, self.localPeers, self.remotePeers)
3503
3505 """
3506 Informal string representation for class instance.
3507 """
3508 return self.__repr__()
3509
3511 """Equals operator, iplemented in terms of original Python 2 compare operator."""
3512 return self.__cmp__(other) == 0
3513
3515 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
3516 return self.__cmp__(other) < 0
3517
3519 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
3520 return self.__cmp__(other) > 0
3521
3523 """
3524 Original Python 2 comparison operator.
3525 Lists within this class are "unordered" for equality comparisons.
3526 @param other: Other object to compare to.
3527 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other.
3528 """
3529 if other is None:
3530 return 1
3531 if self.targetDir != other.targetDir:
3532 if str(self.targetDir or "") < str(other.targetDir or ""):
3533 return -1
3534 else:
3535 return 1
3536 if self.localPeers != other.localPeers:
3537 if self.localPeers < other.localPeers:
3538 return -1
3539 else:
3540 return 1
3541 if self.remotePeers != other.remotePeers:
3542 if self.remotePeers < other.remotePeers:
3543 return -1
3544 else:
3545 return 1
3546 return 0
3547
3549 """
3550 Indicates whether any peers are filled into this object.
3551 @return: Boolean true if any local or remote peers are filled in, false otherwise.
3552 """
3553 return ((self.localPeers is not None and len(self.localPeers) > 0) or
3554 (self.remotePeers is not None and len(self.remotePeers) > 0))
3555
3557 """
3558 Property target used to set the target directory.
3559 The value must be an absolute path if it is not C{None}.
3560 It does not have to exist on disk at the time of assignment.
3561 @raise ValueError: If the value is not an absolute path.
3562 @raise ValueError: If the value cannot be encoded properly.
3563 """
3564 if value is not None:
3565 if not os.path.isabs(value):
3566 raise ValueError("Target directory must be an absolute path.")
3567 self._targetDir = encodePath(value)
3568
3570 """
3571 Property target used to get the target directory.
3572 """
3573 return self._targetDir
3574
3576 """
3577 Property target used to set the local peers list.
3578 Either the value must be C{None} or each element must be a C{LocalPeer}.
3579 @raise ValueError: If the value is not an absolute path.
3580 """
3581 if value is None:
3582 self._localPeers = None
3583 else:
3584 try:
3585 saved = self._localPeers
3586 self._localPeers = ObjectTypeList(LocalPeer, "LocalPeer")
3587 self._localPeers.extend(value)
3588 except Exception as e:
3589 self._localPeers = saved
3590 raise e
3591
3593 """
3594 Property target used to get the local peers list.
3595 """
3596 return self._localPeers
3597
3599 """
3600 Property target used to set the remote peers list.
3601 Either the value must be C{None} or each element must be a C{RemotePeer}.
3602 @raise ValueError: If the value is not a C{RemotePeer}
3603 """
3604 if value is None:
3605 self._remotePeers = None
3606 else:
3607 try:
3608 saved = self._remotePeers
3609 self._remotePeers = ObjectTypeList(RemotePeer, "RemotePeer")
3610 self._remotePeers.extend(value)
3611 except Exception as e:
3612 self._remotePeers = saved
3613 raise e
3614
3616 """
3617 Property target used to get the remote peers list.
3618 """
3619 return self._remotePeers
3620
3621 targetDir = property(_getTargetDir, _setTargetDir, None, "Directory to stage files into, by peer name.")
3622 localPeers = property(_getLocalPeers, _setLocalPeers, None, "List of local peers.")
3623 remotePeers = property(_getRemotePeers, _setRemotePeers, None, "List of remote peers.")
3624
3625
3626
3627
3628
3629
3630 @total_ordering
3631 -class StoreConfig(object):
3632
3633 """
3634 Class representing a Cedar Backup store configuration.
3635
3636 The following restrictions exist on data in this class:
3637
3638 - The source directory must be an absolute path.
3639 - The media type must be one of the values in L{VALID_MEDIA_TYPES}.
3640 - The device type must be one of the values in L{VALID_DEVICE_TYPES}.
3641 - The device path must be an absolute path.
3642 - The SCSI id, if provided, must be in the form specified by L{validateScsiId}.
3643 - The drive speed must be an integer >= 1
3644 - The blanking behavior must be a C{BlankBehavior} object
3645 - The refresh media delay must be an integer >= 0
3646 - The eject delay must be an integer >= 0
3647
3648 Note that although the blanking factor must be a positive floating point
3649 number, it is stored as a string. This is done so that we can losslessly go
3650 back and forth between XML and object representations of configuration.
3651
3652 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__, sourceDir,
3653 mediaType, deviceType, devicePath, deviceScsiId,
3654 driveSpeed, checkData, checkMedia, warnMidnite, noEject,
3655 blankBehavior, refreshMediaDelay, ejectDelay
3656 """
3657
3658 - def __init__(self, sourceDir=None, mediaType=None, deviceType=None,
3659 devicePath=None, deviceScsiId=None, driveSpeed=None,
3660 checkData=False, warnMidnite=False, noEject=False,
3661 checkMedia=False, blankBehavior=None, refreshMediaDelay=None,
3662 ejectDelay=None):
3663 """
3664 Constructor for the C{StoreConfig} class.
3665
3666 @param sourceDir: Directory whose contents should be written to media.
3667 @param mediaType: Type of the media (see notes above).
3668 @param deviceType: Type of the device (optional, see notes above).
3669 @param devicePath: Filesystem device name for writer device, i.e. C{/dev/cdrw}.
3670 @param deviceScsiId: SCSI id for writer device, i.e. C{[<method>:]scsibus,target,lun}.
3671 @param driveSpeed: Speed of the drive, i.e. C{2} for 2x drive, etc.
3672 @param checkData: Whether resulting image should be validated.
3673 @param checkMedia: Whether media should be checked before being written to.
3674 @param warnMidnite: Whether to generate warnings for crossing midnite.
3675 @param noEject: Indicates that the writer device should not be ejected.
3676 @param blankBehavior: Controls optimized blanking behavior.
3677 @param refreshMediaDelay: Delay, in seconds, to add after refreshing media
3678 @param ejectDelay: Delay, in seconds, to add after ejecting media before closing the tray
3679
3680 @raise ValueError: If one of the values is invalid.
3681 """
3682 self._sourceDir = None
3683 self._mediaType = None
3684 self._deviceType = None
3685 self._devicePath = None
3686 self._deviceScsiId = None
3687 self._driveSpeed = None
3688 self._checkData = None
3689 self._checkMedia = None
3690 self._warnMidnite = None
3691 self._noEject = None
3692 self._blankBehavior = None
3693 self._refreshMediaDelay = None
3694 self._ejectDelay = None
3695 self.sourceDir = sourceDir
3696 self.mediaType = mediaType
3697 self.deviceType = deviceType
3698 self.devicePath = devicePath
3699 self.deviceScsiId = deviceScsiId
3700 self.driveSpeed = driveSpeed
3701 self.checkData = checkData
3702 self.checkMedia = checkMedia
3703 self.warnMidnite = warnMidnite
3704 self.noEject = noEject
3705 self.blankBehavior = blankBehavior
3706 self.refreshMediaDelay = refreshMediaDelay
3707 self.ejectDelay = ejectDelay
3708
3710 """
3711 Official string representation for class instance.
3712 """
3713 return "StoreConfig(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" % (
3714 self.sourceDir, self.mediaType, self.deviceType,
3715 self.devicePath, self.deviceScsiId, self.driveSpeed,
3716 self.checkData, self.warnMidnite, self.noEject,
3717 self.checkMedia, self.blankBehavior, self.refreshMediaDelay,
3718 self.ejectDelay)
3719
3721 """
3722 Informal string representation for class instance.
3723 """
3724 return self.__repr__()
3725
3727 """Equals operator, iplemented in terms of original Python 2 compare operator."""
3728 return self.__cmp__(other) == 0
3729
3731 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
3732 return self.__cmp__(other) < 0
3733
3735 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
3736 return self.__cmp__(other) > 0
3737
3812
3814 """
3815 Property target used to set the source directory.
3816 The value must be an absolute path if it is not C{None}.
3817 It does not have to exist on disk at the time of assignment.
3818 @raise ValueError: If the value is not an absolute path.
3819 @raise ValueError: If the value cannot be encoded properly.
3820 """
3821 if value is not None:
3822 if not os.path.isabs(value):
3823 raise ValueError("Source directory must be an absolute path.")
3824 self._sourceDir = encodePath(value)
3825
3827 """
3828 Property target used to get the source directory.
3829 """
3830 return self._sourceDir
3831
3842
3848
3850 """
3851 Property target used to set the device type.
3852 The value must be one of L{VALID_DEVICE_TYPES}.
3853 @raise ValueError: If the value is not valid.
3854 """
3855 if value is not None:
3856 if value not in VALID_DEVICE_TYPES:
3857 raise ValueError("Device type must be one of %s." % VALID_DEVICE_TYPES)
3858 self._deviceType = value
3859
3861 """
3862 Property target used to get the device type.
3863 """
3864 return self._deviceType
3865
3867 """
3868 Property target used to set the device path.
3869 The value must be an absolute path if it is not C{None}.
3870 It does not have to exist on disk at the time of assignment.
3871 @raise ValueError: If the value is not an absolute path.
3872 @raise ValueError: If the value cannot be encoded properly.
3873 """
3874 if value is not None:
3875 if not os.path.isabs(value):
3876 raise ValueError("Device path must be an absolute path.")
3877 self._devicePath = encodePath(value)
3878
3880 """
3881 Property target used to get the device path.
3882 """
3883 return self._devicePath
3884
3886 """
3887 Property target used to set the SCSI id
3888 The SCSI id must be valid per L{validateScsiId}.
3889 @raise ValueError: If the value is not valid.
3890 """
3891 if value is None:
3892 self._deviceScsiId = None
3893 else:
3894 self._deviceScsiId = validateScsiId(value)
3895
3897 """
3898 Property target used to get the SCSI id.
3899 """
3900 return self._deviceScsiId
3901
3903 """
3904 Property target used to set the drive speed.
3905 The drive speed must be valid per L{validateDriveSpeed}.
3906 @raise ValueError: If the value is not valid.
3907 """
3908 self._driveSpeed = validateDriveSpeed(value)
3909
3911 """
3912 Property target used to get the drive speed.
3913 """
3914 return self._driveSpeed
3915
3917 """
3918 Property target used to set the check data flag.
3919 No validations, but we normalize the value to C{True} or C{False}.
3920 """
3921 if value:
3922 self._checkData = True
3923 else:
3924 self._checkData = False
3925
3927 """
3928 Property target used to get the check data flag.
3929 """
3930 return self._checkData
3931
3941
3947
3949 """
3950 Property target used to set the midnite warning flag.
3951 No validations, but we normalize the value to C{True} or C{False}.
3952 """
3953 if value:
3954 self._warnMidnite = True
3955 else:
3956 self._warnMidnite = False
3957
3959 """
3960 Property target used to get the midnite warning flag.
3961 """
3962 return self._warnMidnite
3963
3965 """
3966 Property target used to set the no-eject flag.
3967 No validations, but we normalize the value to C{True} or C{False}.
3968 """
3969 if value:
3970 self._noEject = True
3971 else:
3972 self._noEject = False
3973
3975 """
3976 Property target used to get the no-eject flag.
3977 """
3978 return self._noEject
3979
3981 """
3982 Property target used to set blanking behavior configuration.
3983 If not C{None}, the value must be a C{BlankBehavior} object.
3984 @raise ValueError: If the value is not a C{BlankBehavior}
3985 """
3986 if value is None:
3987 self._blankBehavior = None
3988 else:
3989 if not isinstance(value, BlankBehavior):
3990 raise ValueError("Value must be a C{BlankBehavior} object.")
3991 self._blankBehavior = value
3992
3994 """
3995 Property target used to get the blanking behavior configuration.
3996 """
3997 return self._blankBehavior
3998
4017
4023
4025 """
4026 Property target used to set the ejectDelay.
4027 The value must be an integer >= 0.
4028 @raise ValueError: If the value is not valid.
4029 """
4030 if value is None:
4031 self._ejectDelay = None
4032 else:
4033 try:
4034 value = int(value)
4035 except TypeError:
4036 raise ValueError("Action ejectDelay value must be an integer >= 0.")
4037 if value < 0:
4038 raise ValueError("Action ejectDelay value must be an integer >= 0.")
4039 if value == 0:
4040 value = None
4041 self._ejectDelay = value
4042
4044 """
4045 Property target used to get the action ejectDelay.
4046 """
4047 return self._ejectDelay
4048
4049 sourceDir = property(_getSourceDir, _setSourceDir, None, "Directory whose contents should be written to media.")
4050 mediaType = property(_getMediaType, _setMediaType, None, "Type of the media (see notes above).")
4051 deviceType = property(_getDeviceType, _setDeviceType, None, "Type of the device (optional, see notes above).")
4052 devicePath = property(_getDevicePath, _setDevicePath, None, "Filesystem device name for writer device.")
4053 deviceScsiId = property(_getDeviceScsiId, _setDeviceScsiId, None, "SCSI id for writer device (optional, see notes above).")
4054 driveSpeed = property(_getDriveSpeed, _setDriveSpeed, None, "Speed of the drive.")
4055 checkData = property(_getCheckData, _setCheckData, None, "Whether resulting image should be validated.")
4056 checkMedia = property(_getCheckMedia, _setCheckMedia, None, "Whether media should be checked before being written to.")
4057 warnMidnite = property(_getWarnMidnite, _setWarnMidnite, None, "Whether to generate warnings for crossing midnite.")
4058 noEject = property(_getNoEject, _setNoEject, None, "Indicates that the writer device should not be ejected.")
4059 blankBehavior = property(_getBlankBehavior, _setBlankBehavior, None, "Controls optimized blanking behavior.")
4060 refreshMediaDelay = property(_getRefreshMediaDelay, _setRefreshMediaDelay, None, "Delay, in seconds, to add after refreshing media.")
4061 ejectDelay = property(_getEjectDelay, _setEjectDelay, None, "Delay, in seconds, to add after ejecting media before closing the tray")
4062
4063
4064
4065
4066
4067
4068 @total_ordering
4069 -class PurgeConfig(object):
4070
4071 """
4072 Class representing a Cedar Backup purge configuration.
4073
4074 The following restrictions exist on data in this class:
4075
4076 - The purge directory list must be a list of C{PurgeDir} objects.
4077
4078 For the C{purgeDirs} list, validation is accomplished through the
4079 L{util.ObjectTypeList} list implementation that overrides common list
4080 methods and transparently ensures that each element is a C{PurgeDir}.
4081
4082 @note: Lists within this class are "unordered" for equality comparisons.
4083
4084 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__, purgeDirs
4085 """
4086
4088 """
4089 Constructor for the C{Purge} class.
4090 @param purgeDirs: List of purge directories.
4091 @raise ValueError: If one of the values is invalid.
4092 """
4093 self._purgeDirs = None
4094 self.purgeDirs = purgeDirs
4095
4097 """
4098 Official string representation for class instance.
4099 """
4100 return "PurgeConfig(%s)" % self.purgeDirs
4101
4103 """
4104 Informal string representation for class instance.
4105 """
4106 return self.__repr__()
4107
4109 """Equals operator, iplemented in terms of original Python 2 compare operator."""
4110 return self.__cmp__(other) == 0
4111
4113 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
4114 return self.__cmp__(other) < 0
4115
4117 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
4118 return self.__cmp__(other) > 0
4119
4121 """
4122 Original Python 2 comparison operator.
4123 Lists within this class are "unordered" for equality comparisons.
4124 @param other: Other object to compare to.
4125 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other.
4126 """
4127 if other is None:
4128 return 1
4129 if self.purgeDirs != other.purgeDirs:
4130 if self.purgeDirs < other.purgeDirs:
4131 return -1
4132 else:
4133 return 1
4134 return 0
4135
4137 """
4138 Property target used to set the purge dirs list.
4139 Either the value must be C{None} or each element must be a C{PurgeDir}.
4140 @raise ValueError: If the value is not a C{PurgeDir}
4141 """
4142 if value is None:
4143 self._purgeDirs = None
4144 else:
4145 try:
4146 saved = self._purgeDirs
4147 self._purgeDirs = ObjectTypeList(PurgeDir, "PurgeDir")
4148 self._purgeDirs.extend(value)
4149 except Exception as e:
4150 self._purgeDirs = saved
4151 raise e
4152
4154 """
4155 Property target used to get the purge dirs list.
4156 """
4157 return self._purgeDirs
4158
4159 purgeDirs = property(_getPurgeDirs, _setPurgeDirs, None, "List of directories to purge.")
4160
4161
4162
4163
4164
4165
4166 @total_ordering
4167 -class Config(object):
4168
4169
4170
4171
4172
4173 """
4174 Class representing a Cedar Backup XML configuration document.
4175
4176 The C{Config} class is a Python object representation of a Cedar Backup XML
4177 configuration file. It is intended to be the only Python-language interface
4178 to Cedar Backup configuration on disk for both Cedar Backup itself and for
4179 external applications.
4180
4181 The object representation is two-way: XML data can be used to create a
4182 C{Config} object, and then changes to the object can be propogated back to
4183 disk. A C{Config} object can even be used to create a configuration file
4184 from scratch programmatically.
4185
4186 This class and the classes it is composed from often use Python's
4187 C{property} construct to validate input and limit access to values. Some
4188 validations can only be done once a document is considered "complete"
4189 (see module notes for more details).
4190
4191 Assignments to the various instance variables must match the expected
4192 type, i.e. C{reference} must be a C{ReferenceConfig}. The internal check
4193 uses the built-in C{isinstance} function, so it should be OK to use
4194 subclasses if you want to.
4195
4196 If an instance variable is not set, its value will be C{None}. When an
4197 object is initialized without using an XML document, all of the values
4198 will be C{None}. Even when an object is initialized using XML, some of
4199 the values might be C{None} because not every section is required.
4200
4201 @note: Lists within this class are "unordered" for equality comparisons.
4202
4203 @sort: __init__, __repr__, __str__, __cmp__, __eq__, __lt__, __gt__, extractXml, validate,
4204 reference, extensions, options, collect, stage, store, purge,
4205 _getReference, _setReference, _getExtensions, _setExtensions,
4206 _getOptions, _setOptions, _getPeers, _setPeers, _getCollect,
4207 _setCollect, _getStage, _setStage, _getStore, _setStore,
4208 _getPurge, _setPurge
4209 """
4210
4211
4212
4213
4214
4215 - def __init__(self, xmlData=None, xmlPath=None, validate=True):
4216 """
4217 Initializes a configuration object.
4218
4219 If you initialize the object without passing either C{xmlData} or
4220 C{xmlPath}, then configuration will be empty and will be invalid until it
4221 is filled in properly.
4222
4223 No reference to the original XML data or original path is saved off by
4224 this class. Once the data has been parsed (successfully or not) this
4225 original information is discarded.
4226
4227 Unless the C{validate} argument is C{False}, the L{Config.validate}
4228 method will be called (with its default arguments) against configuration
4229 after successfully parsing any passed-in XML. Keep in mind that even if
4230 C{validate} is C{False}, it might not be possible to parse the passed-in
4231 XML document if lower-level validations fail.
4232
4233 @note: It is strongly suggested that the C{validate} option always be set
4234 to C{True} (the default) unless there is a specific need to read in
4235 invalid configuration from disk.
4236
4237 @param xmlData: XML data representing configuration.
4238 @type xmlData: String data.
4239
4240 @param xmlPath: Path to an XML file on disk.
4241 @type xmlPath: Absolute path to a file on disk.
4242
4243 @param validate: Validate the document after parsing it.
4244 @type validate: Boolean true/false.
4245
4246 @raise ValueError: If both C{xmlData} and C{xmlPath} are passed-in.
4247 @raise ValueError: If the XML data in C{xmlData} or C{xmlPath} cannot be parsed.
4248 @raise ValueError: If the parsed configuration document is not valid.
4249 """
4250 self._reference = None
4251 self._extensions = None
4252 self._options = None
4253 self._peers = None
4254 self._collect = None
4255 self._stage = None
4256 self._store = None
4257 self._purge = None
4258 self.reference = None
4259 self.extensions = None
4260 self.options = None
4261 self.peers = None
4262 self.collect = None
4263 self.stage = None
4264 self.store = None
4265 self.purge = None
4266 if xmlData is not None and xmlPath is not None:
4267 raise ValueError("Use either xmlData or xmlPath, but not both.")
4268 if xmlData is not None:
4269 self._parseXmlData(xmlData)
4270 if validate:
4271 self.validate()
4272 elif xmlPath is not None:
4273 with open(xmlPath) as f:
4274 xmlData = f.read()
4275 self._parseXmlData(xmlData)
4276 if validate:
4277 self.validate()
4278
4279
4280
4281
4282
4283
4285 """
4286 Official string representation for class instance.
4287 """
4288 return "Config(%s, %s, %s, %s, %s, %s, %s, %s)" % (self.reference, self.extensions, self.options,
4289 self.peers, self.collect, self.stage, self.store,
4290 self.purge)
4291
4293 """
4294 Informal string representation for class instance.
4295 """
4296 return self.__repr__()
4297
4298
4299
4300
4301
4302
4304 """Equals operator, iplemented in terms of original Python 2 compare operator."""
4305 return self.__cmp__(other) == 0
4306
4308 """Less-than operator, iplemented in terms of original Python 2 compare operator."""
4309 return self.__cmp__(other) < 0
4310
4312 """Greater-than operator, iplemented in terms of original Python 2 compare operator."""
4313 return self.__cmp__(other) > 0
4314
4316 """
4317 Original Python 2 comparison operator.
4318 Lists within this class are "unordered" for equality comparisons.
4319 @param other: Other object to compare to.
4320 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other.
4321 """
4322 if other is None:
4323 return 1
4324 if self.reference != other.reference:
4325 if self.reference < other.reference:
4326 return -1
4327 else:
4328 return 1
4329 if self.extensions != other.extensions:
4330 if self.extensions < other.extensions:
4331 return -1
4332 else:
4333 return 1
4334 if self.options != other.options:
4335 if self.options < other.options:
4336 return -1
4337 else:
4338 return 1
4339 if self.peers != other.peers:
4340 if self.peers < other.peers:
4341 return -1
4342 else:
4343 return 1
4344 if self.collect != other.collect:
4345 if self.collect < other.collect:
4346 return -1
4347 else:
4348 return 1
4349 if self.stage != other.stage:
4350 if self.stage < other.stage:
4351 return -1
4352 else:
4353 return 1
4354 if self.store != other.store:
4355 if self.store < other.store:
4356 return -1
4357 else:
4358 return 1
4359 if self.purge != other.purge:
4360 if self.purge < other.purge:
4361 return -1
4362 else:
4363 return 1
4364 return 0
4365
4366
4367
4368
4369
4370
4372 """
4373 Property target used to set the reference configuration value.
4374 If not C{None}, the value must be a C{ReferenceConfig} object.
4375 @raise ValueError: If the value is not a C{ReferenceConfig}
4376 """
4377 if value is None:
4378 self._reference = None
4379 else:
4380 if not isinstance(value, ReferenceConfig):
4381 raise ValueError("Value must be a C{ReferenceConfig} object.")
4382 self._reference = value
4383
4385 """
4386 Property target used to get the reference configuration value.
4387 """
4388 return self._reference
4389
4390 - def _setExtensions(self, value):
4391 """
4392 Property target used to set the extensions configuration value.
4393 If not C{None}, the value must be a C{ExtensionsConfig} object.
4394 @raise ValueError: If the value is not a C{ExtensionsConfig}
4395 """
4396 if value is None:
4397 self._extensions = None
4398 else:
4399 if not isinstance(value, ExtensionsConfig):
4400 raise ValueError("Value must be a C{ExtensionsConfig} object.")
4401 self._extensions = value
4402
4403 - def _getExtensions(self):
4404 """
4405 Property target used to get the extensions configuration value.
4406 """
4407 return self._extensions
4408
4410 """
4411 Property target used to set the options configuration value.
4412 If not C{None}, the value must be an C{OptionsConfig} object.
4413 @raise ValueError: If the value is not a C{OptionsConfig}
4414 """
4415 if value is None:
4416 self._options = None
4417 else:
4418 if not isinstance(value, OptionsConfig):
4419 raise ValueError("Value must be a C{OptionsConfig} object.")
4420 self._options = value
4421
4423 """
4424 Property target used to get the options configuration value.
4425 """
4426 return self._options
4427
4429 """
4430 Property target used to set the peers configuration value.
4431 If not C{None}, the value must be an C{PeersConfig} object.
4432 @raise ValueError: If the value is not a C{PeersConfig}
4433 """
4434 if value is None:
4435 self._peers = None
4436 else:
4437 if not isinstance(value, PeersConfig):
4438 raise ValueError("Value must be a C{PeersConfig} object.")
4439 self._peers = value
4440
4442 """
4443 Property target used to get the peers configuration value.
4444 """
4445 return self._peers
4446
4448 """
4449 Property target used to set the collect configuration value.
4450 If not C{None}, the value must be a C{CollectConfig} object.
4451 @raise ValueError: If the value is not a C{CollectConfig}
4452 """
4453 if value is None:
4454 self._collect = None
4455 else:
4456 if not isinstance(value, CollectConfig):
4457 raise ValueError("Value must be a C{CollectConfig} object.")
4458 self._collect = value
4459
4461 """
4462 Property target used to get the collect configuration value.
4463 """
4464 return self._collect
4465
4467 """
4468 Property target used to set the stage configuration value.
4469 If not C{None}, the value must be a C{StageConfig} object.
4470 @raise ValueError: If the value is not a C{StageConfig}
4471 """
4472 if value is None:
4473 self._stage = None
4474 else:
4475 if not isinstance(value, StageConfig):
4476 raise ValueError("Value must be a C{StageConfig} object.")
4477 self._stage = value
4478
4480 """
4481 Property target used to get the stage configuration value.
4482 """
4483 return self._stage
4484
4486 """
4487 Property target used to set the store configuration value.
4488 If not C{None}, the value must be a C{StoreConfig} object.
4489 @raise ValueError: If the value is not a C{StoreConfig}
4490 """
4491 if value is None:
4492 self._store = None
4493 else:
4494 if not isinstance(value, StoreConfig):
4495 raise ValueError("Value must be a C{StoreConfig} object.")
4496 self._store = value
4497
4499 """
4500 Property target used to get the store configuration value.
4501 """
4502 return self._store
4503
4505 """
4506 Property target used to set the purge configuration value.
4507 If not C{None}, the value must be a C{PurgeConfig} object.
4508 @raise ValueError: If the value is not a C{PurgeConfig}
4509 """
4510 if value is None:
4511 self._purge = None
4512 else:
4513 if not isinstance(value, PurgeConfig):
4514 raise ValueError("Value must be a C{PurgeConfig} object.")
4515 self._purge = value
4516
4518 """
4519 Property target used to get the purge configuration value.
4520 """
4521 return self._purge
4522
4523 reference = property(_getReference, _setReference, None, "Reference configuration in terms of a C{ReferenceConfig} object.")
4524 extensions = property(_getExtensions, _setExtensions, None, "Extensions configuration in terms of a C{ExtensionsConfig} object.")
4525 options = property(_getOptions, _setOptions, None, "Options configuration in terms of a C{OptionsConfig} object.")
4526 peers = property(_getPeers, _setPeers, None, "Peers configuration in terms of a C{PeersConfig} object.")
4527 collect = property(_getCollect, _setCollect, None, "Collect configuration in terms of a C{CollectConfig} object.")
4528 stage = property(_getStage, _setStage, None, "Stage configuration in terms of a C{StageConfig} object.")
4529 store = property(_getStore, _setStore, None, "Store configuration in terms of a C{StoreConfig} object.")
4530 purge = property(_getPurge, _setPurge, None, "Purge configuration in terms of a C{PurgeConfig} object.")
4531
4532
4533
4534
4535
4536
4538 """
4539 Extracts configuration into an XML document.
4540
4541 If C{xmlPath} is not provided, then the XML document will be returned as
4542 a string. If C{xmlPath} is provided, then the XML document will be written
4543 to the file and C{None} will be returned.
4544
4545 Unless the C{validate} parameter is C{False}, the L{Config.validate}
4546 method will be called (with its default arguments) against the
4547 configuration before extracting the XML. If configuration is not valid,
4548 then an XML document will not be extracted.
4549
4550 @note: It is strongly suggested that the C{validate} option always be set
4551 to C{True} (the default) unless there is a specific need to write an
4552 invalid configuration file to disk.
4553
4554 @param xmlPath: Path to an XML file to create on disk.
4555 @type xmlPath: Absolute path to a file.
4556
4557 @param validate: Validate the document before extracting it.
4558 @type validate: Boolean true/false.
4559
4560 @return: XML string data or C{None} as described above.
4561
4562 @raise ValueError: If configuration within the object is not valid.
4563 @raise IOError: If there is an error writing to the file.
4564 @raise OSError: If there is an error writing to the file.
4565 """
4566 if validate:
4567 self.validate()
4568 xmlData = self._extractXml()
4569 if xmlPath is not None:
4570 with open(xmlPath, "w") as f:
4571 f.write(xmlData)
4572 return None
4573 else:
4574 return xmlData
4575
4576 - def validate(self, requireOneAction=True, requireReference=False, requireExtensions=False, requireOptions=True,
4577 requireCollect=False, requireStage=False, requireStore=False, requirePurge=False, requirePeers=False):
4578 """
4579 Validates configuration represented by the object.
4580
4581 This method encapsulates all of the validations that should apply to a
4582 fully "complete" document but are not already taken care of by earlier
4583 validations. It also provides some extra convenience functionality which
4584 might be useful to some people. The process of validation is laid out in
4585 the I{Validation} section in the class notes (above).
4586
4587 @param requireOneAction: Require at least one of the collect, stage, store or purge sections.
4588 @param requireReference: Require the reference section.
4589 @param requireExtensions: Require the extensions section.
4590 @param requireOptions: Require the options section.
4591 @param requirePeers: Require the peers section.
4592 @param requireCollect: Require the collect section.
4593 @param requireStage: Require the stage section.
4594 @param requireStore: Require the store section.
4595 @param requirePurge: Require the purge section.
4596
4597 @raise ValueError: If one of the validations fails.
4598 """
4599 if requireOneAction and (self.collect, self.stage, self.store, self.purge) == (None, None, None, None):
4600 raise ValueError("At least one of the collect, stage, store and purge sections is required.")
4601 if requireReference and self.reference is None:
4602 raise ValueError("The reference is section is required.")
4603 if requireExtensions and self.extensions is None:
4604 raise ValueError("The extensions is section is required.")
4605 if requireOptions and self.options is None:
4606 raise ValueError("The options is section is required.")
4607 if requirePeers and self.peers is None:
4608 raise ValueError("The peers is section is required.")
4609 if requireCollect and self.collect is None:
4610 raise ValueError("The collect is section is required.")
4611 if requireStage and self.stage is None:
4612 raise ValueError("The stage is section is required.")
4613 if requireStore and self.store is None:
4614 raise ValueError("The store is section is required.")
4615 if requirePurge and self.purge is None:
4616 raise ValueError("The purge is section is required.")
4617 self._validateContents()
4618
4619
4620
4621
4622
4623
4625 """
4626 Internal method to parse an XML string into the object.
4627
4628 This method parses the XML document into a DOM tree (C{xmlDom}) and then
4629 calls individual static methods to parse each of the individual
4630 configuration sections.
4631
4632 Most of the validation we do here has to do with whether the document can
4633 be parsed and whether any values which exist are valid. We don't do much
4634 validation as to whether required elements actually exist unless we have
4635 to to make sense of the document (instead, that's the job of the
4636 L{validate} method).
4637
4638 @param xmlData: XML data to be parsed
4639 @type xmlData: String data
4640
4641 @raise ValueError: If the XML cannot be successfully parsed.
4642 """
4643 (xmlDom, parentNode) = createInputDom(xmlData)
4644 self._reference = Config._parseReference(parentNode)
4645 self._extensions = Config._parseExtensions(parentNode)
4646 self._options = Config._parseOptions(parentNode)
4647 self._peers = Config._parsePeers(parentNode)
4648 self._collect = Config._parseCollect(parentNode)
4649 self._stage = Config._parseStage(parentNode)
4650 self._store = Config._parseStore(parentNode)
4651 self._purge = Config._parsePurge(parentNode)
4652
4653 @staticmethod
4655 """
4656 Parses a reference configuration section.
4657
4658 We read the following fields::
4659
4660 author //cb_config/reference/author
4661 revision //cb_config/reference/revision
4662 description //cb_config/reference/description
4663 generator //cb_config/reference/generator
4664
4665 @param parentNode: Parent node to search beneath.
4666
4667 @return: C{ReferenceConfig} object or C{None} if the section does not exist.
4668 @raise ValueError: If some filled-in value is invalid.
4669 """
4670 reference = None
4671 sectionNode = readFirstChild(parentNode, "reference")
4672 if sectionNode is not None:
4673 reference = ReferenceConfig()
4674 reference.author = readString(sectionNode, "author")
4675 reference.revision = readString(sectionNode, "revision")
4676 reference.description = readString(sectionNode, "description")
4677 reference.generator = readString(sectionNode, "generator")
4678 return reference
4679
4680 @staticmethod
4682 """
4683 Parses an extensions configuration section.
4684
4685 We read the following fields::
4686
4687 orderMode //cb_config/extensions/order_mode
4688
4689 We also read groups of the following items, one list element per item::
4690
4691 name //cb_config/extensions/action/name
4692 module //cb_config/extensions/action/module
4693 function //cb_config/extensions/action/function
4694 index //cb_config/extensions/action/index
4695 dependencies //cb_config/extensions/action/depends
4696
4697 The extended actions are parsed by L{_parseExtendedActions}.
4698
4699 @param parentNode: Parent node to search beneath.
4700
4701 @return: C{ExtensionsConfig} object or C{None} if the section does not exist.
4702 @raise ValueError: If some filled-in value is invalid.
4703 """
4704 extensions = None
4705 sectionNode = readFirstChild(parentNode, "extensions")
4706 if sectionNode is not None:
4707 extensions = ExtensionsConfig()
4708 extensions.orderMode = readString(sectionNode, "order_mode")
4709 extensions.actions = Config._parseExtendedActions(sectionNode)
4710 return extensions
4711
4712 @staticmethod
4714 """
4715 Parses a options configuration section.
4716
4717 We read the following fields::
4718
4719 startingDay //cb_config/options/starting_day
4720 workingDir //cb_config/options/working_dir
4721 backupUser //cb_config/options/backup_user
4722 backupGroup //cb_config/options/backup_group
4723 rcpCommand //cb_config/options/rcp_command
4724 rshCommand //cb_config/options/rsh_command
4725 cbackCommand //cb_config/options/cback_command
4726 managedActions //cb_config/options/managed_actions
4727
4728 The list of managed actions is a comma-separated list of action names.
4729
4730 We also read groups of the following items, one list element per
4731 item::
4732
4733 overrides //cb_config/options/override
4734 hooks //cb_config/options/hook
4735
4736 The overrides are parsed by L{_parseOverrides} and the hooks are parsed
4737 by L{_parseHooks}.
4738
4739 @param parentNode: Parent node to search beneath.
4740
4741 @return: C{OptionsConfig} object or C{None} if the section does not exist.
4742 @raise ValueError: If some filled-in value is invalid.
4743 """
4744 options = None
4745 sectionNode = readFirstChild(parentNode, "options")
4746 if sectionNode is not None:
4747 options = OptionsConfig()
4748 options.startingDay = readString(sectionNode, "starting_day")
4749 options.workingDir = readString(sectionNode, "working_dir")
4750 options.backupUser = readString(sectionNode, "backup_user")
4751 options.backupGroup = readString(sectionNode, "backup_group")
4752 options.rcpCommand = readString(sectionNode, "rcp_command")
4753 options.rshCommand = readString(sectionNode, "rsh_command")
4754 options.cbackCommand = readString(sectionNode, "cback_command")
4755 options.overrides = Config._parseOverrides(sectionNode)
4756 options.hooks = Config._parseHooks(sectionNode)
4757 managedActions = readString(sectionNode, "managed_actions")
4758 options.managedActions = parseCommaSeparatedString(managedActions)
4759 return options
4760
4761 @staticmethod
4763 """
4764 Parses a peers configuration section.
4765
4766 We read groups of the following items, one list element per
4767 item::
4768
4769 localPeers //cb_config/stage/peer
4770 remotePeers //cb_config/stage/peer
4771
4772 The individual peer entries are parsed by L{_parsePeerList}.
4773
4774 @param parentNode: Parent node to search beneath.
4775
4776 @return: C{StageConfig} object or C{None} if the section does not exist.
4777 @raise ValueError: If some filled-in value is invalid.
4778 """
4779 peers = None
4780 sectionNode = readFirstChild(parentNode, "peers")
4781 if sectionNode is not None:
4782 peers = PeersConfig()
4783 (peers.localPeers, peers.remotePeers) = Config._parsePeerList(sectionNode)
4784 return peers
4785
4786 @staticmethod
4788 """
4789 Parses a collect configuration section.
4790
4791 We read the following individual fields::
4792
4793 targetDir //cb_config/collect/collect_dir
4794 collectMode //cb_config/collect/collect_mode
4795 archiveMode //cb_config/collect/archive_mode
4796 ignoreFile //cb_config/collect/ignore_file
4797
4798 We also read groups of the following items, one list element per
4799 item::
4800
4801 absoluteExcludePaths //cb_config/collect/exclude/abs_path
4802 excludePatterns //cb_config/collect/exclude/pattern
4803 collectFiles //cb_config/collect/file
4804 collectDirs //cb_config/collect/dir
4805
4806 The exclusions are parsed by L{_parseExclusions}, the collect files are
4807 parsed by L{_parseCollectFiles}, and the directories are parsed by
4808 L{_parseCollectDirs}.
4809
4810 @param parentNode: Parent node to search beneath.
4811
4812 @return: C{CollectConfig} object or C{None} if the section does not exist.
4813 @raise ValueError: If some filled-in value is invalid.
4814 """
4815 collect = None
4816 sectionNode = readFirstChild(parentNode, "collect")
4817 if sectionNode is not None:
4818 collect = CollectConfig()
4819 collect.targetDir = readString(sectionNode, "collect_dir")
4820 collect.collectMode = readString(sectionNode, "collect_mode")
4821 collect.archiveMode = readString(sectionNode, "archive_mode")
4822 collect.ignoreFile = readString(sectionNode, "ignore_file")
4823 (collect.absoluteExcludePaths, unused, collect.excludePatterns) = Config._parseExclusions(sectionNode)
4824 collect.collectFiles = Config._parseCollectFiles(sectionNode)
4825 collect.collectDirs = Config._parseCollectDirs(sectionNode)
4826 return collect
4827
4828 @staticmethod
4830 """
4831 Parses a stage configuration section.
4832
4833 We read the following individual fields::
4834
4835 targetDir //cb_config/stage/staging_dir
4836
4837 We also read groups of the following items, one list element per
4838 item::
4839
4840 localPeers //cb_config/stage/peer
4841 remotePeers //cb_config/stage/peer
4842
4843 The individual peer entries are parsed by L{_parsePeerList}.
4844
4845 @param parentNode: Parent node to search beneath.
4846
4847 @return: C{StageConfig} object or C{None} if the section does not exist.
4848 @raise ValueError: If some filled-in value is invalid.
4849 """
4850 stage = None
4851 sectionNode = readFirstChild(parentNode, "stage")
4852 if sectionNode is not None:
4853 stage = StageConfig()
4854 stage.targetDir = readString(sectionNode, "staging_dir")
4855 (stage.localPeers, stage.remotePeers) = Config._parsePeerList(sectionNode)
4856 return stage
4857
4858 @staticmethod
4860 """
4861 Parses a store configuration section.
4862
4863 We read the following fields::
4864
4865 sourceDir //cb_config/store/source_dir
4866 mediaType //cb_config/store/media_type
4867 deviceType //cb_config/store/device_type
4868 devicePath //cb_config/store/target_device
4869 deviceScsiId //cb_config/store/target_scsi_id
4870 driveSpeed //cb_config/store/drive_speed
4871 checkData //cb_config/store/check_data
4872 checkMedia //cb_config/store/check_media
4873 warnMidnite //cb_config/store/warn_midnite
4874 noEject //cb_config/store/no_eject
4875
4876 Blanking behavior configuration is parsed by the C{_parseBlankBehavior}
4877 method.
4878
4879 @param parentNode: Parent node to search beneath.
4880
4881 @return: C{StoreConfig} object or C{None} if the section does not exist.
4882 @raise ValueError: If some filled-in value is invalid.
4883 """
4884 store = None
4885 sectionNode = readFirstChild(parentNode, "store")
4886 if sectionNode is not None:
4887 store = StoreConfig()
4888 store.sourceDir = readString(sectionNode, "source_dir")
4889 store.mediaType = readString(sectionNode, "media_type")
4890 store.deviceType = readString(sectionNode, "device_type")
4891 store.devicePath = readString(sectionNode, "target_device")
4892 store.deviceScsiId = readString(sectionNode, "target_scsi_id")
4893 store.driveSpeed = readInteger(sectionNode, "drive_speed")
4894 store.checkData = readBoolean(sectionNode, "check_data")
4895 store.checkMedia = readBoolean(sectionNode, "check_media")
4896 store.warnMidnite = readBoolean(sectionNode, "warn_midnite")
4897 store.noEject = readBoolean(sectionNode, "no_eject")
4898 store.blankBehavior = Config._parseBlankBehavior(sectionNode)
4899 store.refreshMediaDelay = readInteger(sectionNode, "refresh_media_delay")
4900 store.ejectDelay = readInteger(sectionNode, "eject_delay")
4901 return store
4902
4903 @staticmethod
4905 """
4906 Parses a purge configuration section.
4907
4908 We read groups of the following items, one list element per
4909 item::
4910
4911 purgeDirs //cb_config/purge/dir
4912
4913 The individual directory entries are parsed by L{_parsePurgeDirs}.
4914
4915 @param parentNode: Parent node to search beneath.
4916
4917 @return: C{PurgeConfig} object or C{None} if the section does not exist.
4918 @raise ValueError: If some filled-in value is invalid.
4919 """
4920 purge = None
4921 sectionNode = readFirstChild(parentNode, "purge")
4922 if sectionNode is not None:
4923 purge = PurgeConfig()
4924 purge.purgeDirs = Config._parsePurgeDirs(sectionNode)
4925 return purge
4926
4927 @staticmethod
4929 """
4930 Reads extended actions data from immediately beneath the parent.
4931
4932 We read the following individual fields from each extended action::
4933
4934 name name
4935 module module
4936 function function
4937 index index
4938 dependencies depends
4939
4940 Dependency information is parsed by the C{_parseDependencies} method.
4941
4942 @param parentNode: Parent node to search beneath.
4943
4944 @return: List of extended actions.
4945 @raise ValueError: If the data at the location can't be read
4946 """
4947 lst = []
4948 for entry in readChildren(parentNode, "action"):
4949 if isElement(entry):
4950 action = ExtendedAction()
4951 action.name = readString(entry, "name")
4952 action.module = readString(entry, "module")
4953 action.function = readString(entry, "function")
4954 action.index = readInteger(entry, "index")
4955 action.dependencies = Config._parseDependencies(entry)
4956 lst.append(action)
4957 if lst == []:
4958 lst = None
4959 return lst
4960
4961 @staticmethod
4963 """
4964 Reads exclusions data from immediately beneath the parent.
4965
4966 We read groups of the following items, one list element per item::
4967
4968 absolute exclude/abs_path
4969 relative exclude/rel_path
4970 patterns exclude/pattern
4971
4972 If there are none of some pattern (i.e. no relative path items) then
4973 C{None} will be returned for that item in the tuple.
4974
4975 This method can be used to parse exclusions on both the collect
4976 configuration level and on the collect directory level within collect
4977 configuration.
4978
4979 @param parentNode: Parent node to search beneath.
4980
4981 @return: Tuple of (absolute, relative, patterns) exclusions.
4982 """
4983 sectionNode = readFirstChild(parentNode, "exclude")
4984 if sectionNode is None:
4985 return (None, None, None)
4986 else:
4987 absolute = readStringList(sectionNode, "abs_path")
4988 relative = readStringList(sectionNode, "rel_path")
4989 patterns = readStringList(sectionNode, "pattern")
4990 return (absolute, relative, patterns)
4991
4992 @staticmethod
4994 """
4995 Reads a list of C{CommandOverride} objects from immediately beneath the parent.
4996
4997 We read the following individual fields::
4998
4999 command command
5000 absolutePath abs_path
5001
5002 @param parentNode: Parent node to search beneath.
5003
5004 @return: List of C{CommandOverride} objects or C{None} if none are found.
5005 @raise ValueError: If some filled-in value is invalid.
5006 """
5007 lst = []
5008 for entry in readChildren(parentNode, "override"):
5009 if isElement(entry):
5010 override = CommandOverride()
5011 override.command = readString(entry, "command")
5012 override.absolutePath = readString(entry, "abs_path")
5013 lst.append(override)
5014 if lst == []:
5015 lst = None
5016 return lst
5017
5018 @staticmethod
5020 """
5021 Reads a list of C{ActionHook} objects from immediately beneath the parent.
5022
5023 We read the following individual fields::
5024
5025 action action
5026 command command
5027
5028 @param parentNode: Parent node to search beneath.
5029
5030 @return: List of C{ActionHook} objects or C{None} if none are found.
5031 @raise ValueError: If some filled-in value is invalid.
5032 """
5033 lst = []
5034 for entry in readChildren(parentNode, "pre_action_hook"):
5035 if isElement(entry):
5036 hook = PreActionHook()
5037 hook.action = readString(entry, "action")
5038 hook.command = readString(entry, "command")
5039 lst.append(hook)
5040 for entry in readChildren(parentNode, "post_action_hook"):
5041 if isElement(entry):
5042 hook = PostActionHook()
5043 hook.action = readString(entry, "action")
5044 hook.command = readString(entry, "command")
5045 lst.append(hook)
5046 if lst == []:
5047 lst = None
5048 return lst
5049
5050 @staticmethod
5052 """
5053 Reads a list of C{CollectFile} objects from immediately beneath the parent.
5054
5055 We read the following individual fields::
5056
5057 absolutePath abs_path
5058 collectMode mode I{or} collect_mode
5059 archiveMode archive_mode
5060
5061 The collect mode is a special case. Just a C{mode} tag is accepted, but
5062 we prefer C{collect_mode} for consistency with the rest of the config
5063 file and to avoid confusion with the archive mode. If both are provided,
5064 only C{mode} will be used.
5065
5066 @param parentNode: Parent node to search beneath.
5067
5068 @return: List of C{CollectFile} objects or C{None} if none are found.
5069 @raise ValueError: If some filled-in value is invalid.
5070 """
5071 lst = []
5072 for entry in readChildren(parentNode, "file"):
5073 if isElement(entry):
5074 cfile = CollectFile()
5075 cfile.absolutePath = readString(entry, "abs_path")
5076 cfile.collectMode = readString(entry, "mode")
5077 if cfile.collectMode is None:
5078 cfile.collectMode = readString(entry, "collect_mode")
5079 cfile.archiveMode = readString(entry, "archive_mode")
5080 lst.append(cfile)
5081 if lst == []:
5082 lst = None
5083 return lst
5084
5085 @staticmethod
5087 """
5088 Reads a list of C{CollectDir} objects from immediately beneath the parent.
5089
5090 We read the following individual fields::
5091
5092 absolutePath abs_path
5093 collectMode mode I{or} collect_mode
5094 archiveMode archive_mode
5095 ignoreFile ignore_file
5096 linkDepth link_depth
5097 dereference dereference
5098 recursionLevel recursion_level
5099
5100 The collect mode is a special case. Just a C{mode} tag is accepted for
5101 backwards compatibility, but we prefer C{collect_mode} for consistency
5102 with the rest of the config file and to avoid confusion with the archive
5103 mode. If both are provided, only C{mode} will be used.
5104
5105 We also read groups of the following items, one list element per
5106 item::
5107
5108 absoluteExcludePaths exclude/abs_path
5109 relativeExcludePaths exclude/rel_path
5110 excludePatterns exclude/pattern
5111
5112 The exclusions are parsed by L{_parseExclusions}.
5113
5114 @param parentNode: Parent node to search beneath.
5115
5116 @return: List of C{CollectDir} objects or C{None} if none are found.
5117 @raise ValueError: If some filled-in value is invalid.
5118 """
5119 lst = []
5120 for entry in readChildren(parentNode, "dir"):
5121 if isElement(entry):
5122 cdir = CollectDir()
5123 cdir.absolutePath = readString(entry, "abs_path")
5124 cdir.collectMode = readString(entry, "mode")
5125 if cdir.collectMode is None:
5126 cdir.collectMode = readString(entry, "collect_mode")
5127 cdir.archiveMode = readString(entry, "archive_mode")
5128 cdir.ignoreFile = readString(entry, "ignore_file")
5129 cdir.linkDepth = readInteger(entry, "link_depth")
5130 cdir.dereference = readBoolean(entry, "dereference")
5131 cdir.recursionLevel = readInteger(entry, "recursion_level")
5132 (cdir.absoluteExcludePaths, cdir.relativeExcludePaths, cdir.excludePatterns) = Config._parseExclusions(entry)
5133 lst.append(cdir)
5134 if lst == []:
5135 lst = None
5136 return lst
5137
5138 @staticmethod
5140 """
5141 Reads a list of C{PurgeDir} objects from immediately beneath the parent.
5142
5143 We read the following individual fields::
5144
5145 absolutePath <baseExpr>/abs_path
5146 retainDays <baseExpr>/retain_days
5147
5148 @param parentNode: Parent node to search beneath.
5149
5150 @return: List of C{PurgeDir} objects or C{None} if none are found.
5151 @raise ValueError: If the data at the location can't be read
5152 """
5153 lst = []
5154 for entry in readChildren(parentNode, "dir"):
5155 if isElement(entry):
5156 cdir = PurgeDir()
5157 cdir.absolutePath = readString(entry, "abs_path")
5158 cdir.retainDays = readInteger(entry, "retain_days")
5159 lst.append(cdir)
5160 if lst == []:
5161 lst = None
5162 return lst
5163
5164 @staticmethod
5166 """
5167 Reads remote and local peer data from immediately beneath the parent.
5168
5169 We read the following individual fields for both remote
5170 and local peers::
5171
5172 name name
5173 collectDir collect_dir
5174
5175 We also read the following individual fields for remote peers
5176 only::
5177
5178 remoteUser backup_user
5179 rcpCommand rcp_command
5180 rshCommand rsh_command
5181 cbackCommand cback_command
5182 managed managed
5183 managedActions managed_actions
5184
5185 Additionally, the value in the C{type} field is used to determine whether
5186 this entry is a remote peer. If the type is C{"remote"}, it's a remote
5187 peer, and if the type is C{"local"}, it's a remote peer.
5188
5189 If there are none of one type of peer (i.e. no local peers) then C{None}
5190 will be returned for that item in the tuple.
5191
5192 @param parentNode: Parent node to search beneath.
5193
5194 @return: Tuple of (local, remote) peer lists.
5195 @raise ValueError: If the data at the location can't be read
5196 """
5197 localPeers = []
5198 remotePeers = []
5199 for entry in readChildren(parentNode, "peer"):
5200 if isElement(entry):
5201 peerType = readString(entry, "type")
5202 if peerType == "local":
5203 localPeer = LocalPeer()
5204 localPeer.name = readString(entry, "name")
5205 localPeer.collectDir = readString(entry, "collect_dir")
5206 localPeer.ignoreFailureMode = readString(entry, "ignore_failures")
5207 localPeers.append(localPeer)
5208 elif peerType == "remote":
5209 remotePeer = RemotePeer()
5210 remotePeer.name = readString(entry, "name")
5211 remotePeer.collectDir = readString(entry, "collect_dir")
5212 remotePeer.remoteUser = readString(entry, "backup_user")
5213 remotePeer.rcpCommand = readString(entry, "rcp_command")
5214 remotePeer.rshCommand = readString(entry, "rsh_command")
5215 remotePeer.cbackCommand = readString(entry, "cback_command")
5216 remotePeer.ignoreFailureMode = readString(entry, "ignore_failures")
5217 remotePeer.managed = readBoolean(entry, "managed")
5218 managedActions = readString(entry, "managed_actions")
5219 remotePeer.managedActions = parseCommaSeparatedString(managedActions)
5220 remotePeers.append(remotePeer)
5221 if localPeers == []:
5222 localPeers = None
5223 if remotePeers == []:
5224 remotePeers = None
5225 return (localPeers, remotePeers)
5226
5227 @staticmethod
5229 """
5230 Reads extended action dependency information from a parent node.
5231
5232 We read the following individual fields::
5233
5234 runBefore depends/run_before
5235 runAfter depends/run_after
5236
5237 Each of these fields is a comma-separated list of action names.
5238
5239 The result is placed into an C{ActionDependencies} object.
5240
5241 If the dependencies parent node does not exist, C{None} will be returned.
5242 Otherwise, an C{ActionDependencies} object will always be created, even
5243 if it does not contain any actual dependencies in it.
5244
5245 @param parentNode: Parent node to search beneath.
5246
5247 @return: C{ActionDependencies} object or C{None}.
5248 @raise ValueError: If the data at the location can't be read
5249 """
5250 sectionNode = readFirstChild(parentNode, "depends")
5251 if sectionNode is None:
5252 return None
5253 else:
5254 runBefore = readString(sectionNode, "run_before")
5255 runAfter = readString(sectionNode, "run_after")
5256 beforeList = parseCommaSeparatedString(runBefore)
5257 afterList = parseCommaSeparatedString(runAfter)
5258 return ActionDependencies(beforeList, afterList)
5259
5260 @staticmethod
5262 """
5263 Reads a single C{BlankBehavior} object from immediately beneath the parent.
5264
5265 We read the following individual fields::
5266
5267 blankMode blank_behavior/mode
5268 blankFactor blank_behavior/factor
5269
5270 @param parentNode: Parent node to search beneath.
5271
5272 @return: C{BlankBehavior} object or C{None} if none if the section is not found
5273 @raise ValueError: If some filled-in value is invalid.
5274 """
5275 blankBehavior = None
5276 sectionNode = readFirstChild(parentNode, "blank_behavior")
5277 if sectionNode is not None:
5278 blankBehavior = BlankBehavior()
5279 blankBehavior.blankMode = readString(sectionNode, "mode")
5280 blankBehavior.blankFactor = readString(sectionNode, "factor")
5281 return blankBehavior
5282
5283
5284
5285
5286
5287
5289 """
5290 Internal method to extract configuration into an XML string.
5291
5292 This method assumes that the internal L{validate} method has been called
5293 prior to extracting the XML, if the caller cares. No validation will be
5294 done internally.
5295
5296 As a general rule, fields that are set to C{None} will be extracted into
5297 the document as empty tags. The same goes for container tags that are
5298 filled based on lists - if the list is empty or C{None}, the container
5299 tag will be empty.
5300 """
5301 (xmlDom, parentNode) = createOutputDom()
5302 Config._addReference(xmlDom, parentNode, self.reference)
5303 Config._addExtensions(xmlDom, parentNode, self.extensions)
5304 Config._addOptions(xmlDom, parentNode, self.options)
5305 Config._addPeers(xmlDom, parentNode, self.peers)
5306 Config._addCollect(xmlDom, parentNode, self.collect)
5307 Config._addStage(xmlDom, parentNode, self.stage)
5308 Config._addStore(xmlDom, parentNode, self.store)
5309 Config._addPurge(xmlDom, parentNode, self.purge)
5310 xmlData = serializeDom(xmlDom)
5311 xmlDom.unlink()
5312 return xmlData
5313
5314 @staticmethod
5316 """
5317 Adds a <reference> configuration section as the next child of a parent.
5318
5319 We add the following fields to the document::
5320
5321 author //cb_config/reference/author
5322 revision //cb_config/reference/revision
5323 description //cb_config/reference/description
5324 generator //cb_config/reference/generator
5325
5326 If C{referenceConfig} is C{None}, then no container will be added.
5327
5328 @param xmlDom: DOM tree as from L{createOutputDom}.
5329 @param parentNode: Parent that the section should be appended to.
5330 @param referenceConfig: Reference configuration section to be added to the document.
5331 """
5332 if referenceConfig is not None:
5333 sectionNode = addContainerNode(xmlDom, parentNode, "reference")
5334 addStringNode(xmlDom, sectionNode, "author", referenceConfig.author)
5335 addStringNode(xmlDom, sectionNode, "revision", referenceConfig.revision)
5336 addStringNode(xmlDom, sectionNode, "description", referenceConfig.description)
5337 addStringNode(xmlDom, sectionNode, "generator", referenceConfig.generator)
5338
5339 @staticmethod
5341 """
5342 Adds an <extensions> configuration section as the next child of a parent.
5343
5344 We add the following fields to the document::
5345
5346 order_mode //cb_config/extensions/order_mode
5347
5348 We also add groups of the following items, one list element per item::
5349
5350 actions //cb_config/extensions/action
5351
5352 The extended action entries are added by L{_addExtendedAction}.
5353
5354 If C{extensionsConfig} is C{None}, then no container will be added.
5355
5356 @param xmlDom: DOM tree as from L{createOutputDom}.
5357 @param parentNode: Parent that the section should be appended to.
5358 @param extensionsConfig: Extensions configuration section to be added to the document.
5359 """
5360 if extensionsConfig is not None:
5361 sectionNode = addContainerNode(xmlDom, parentNode, "extensions")
5362 addStringNode(xmlDom, sectionNode, "order_mode", extensionsConfig.orderMode)
5363 if extensionsConfig.actions is not None:
5364 for action in extensionsConfig.actions:
5365 Config._addExtendedAction(xmlDom, sectionNode, action)
5366
5367 @staticmethod
5369 """
5370 Adds a <options> configuration section as the next child of a parent.
5371
5372 We add the following fields to the document::
5373
5374 startingDay //cb_config/options/starting_day
5375 workingDir //cb_config/options/working_dir
5376 backupUser //cb_config/options/backup_user
5377 backupGroup //cb_config/options/backup_group
5378 rcpCommand //cb_config/options/rcp_command
5379 rshCommand //cb_config/options/rsh_command
5380 cbackCommand //cb_config/options/cback_command
5381 managedActions //cb_config/options/managed_actions
5382
5383 We also add groups of the following items, one list element per
5384 item::
5385
5386 overrides //cb_config/options/override
5387 hooks //cb_config/options/pre_action_hook
5388 hooks //cb_config/options/post_action_hook
5389
5390 The individual override items are added by L{_addOverride}. The
5391 individual hook items are added by L{_addHook}.
5392
5393 If C{optionsConfig} is C{None}, then no container will be added.
5394
5395 @param xmlDom: DOM tree as from L{createOutputDom}.
5396 @param parentNode: Parent that the section should be appended to.
5397 @param optionsConfig: Options configuration section to be added to the document.
5398 """
5399 if optionsConfig is not None:
5400 sectionNode = addContainerNode(xmlDom, parentNode, "options")
5401 addStringNode(xmlDom, sectionNode, "starting_day", optionsConfig.startingDay)
5402 addStringNode(xmlDom, sectionNode, "working_dir", optionsConfig.workingDir)
5403 addStringNode(xmlDom, sectionNode, "backup_user", optionsConfig.backupUser)
5404 addStringNode(xmlDom, sectionNode, "backup_group", optionsConfig.backupGroup)
5405 addStringNode(xmlDom, sectionNode, "rcp_command", optionsConfig.rcpCommand)
5406 addStringNode(xmlDom, sectionNode, "rsh_command", optionsConfig.rshCommand)
5407 addStringNode(xmlDom, sectionNode, "cback_command", optionsConfig.cbackCommand)
5408 managedActions = Config._buildCommaSeparatedString(optionsConfig.managedActions)
5409 addStringNode(xmlDom, sectionNode, "managed_actions", managedActions)
5410 if optionsConfig.overrides is not None:
5411 for override in optionsConfig.overrides:
5412 Config._addOverride(xmlDom, sectionNode, override)
5413 if optionsConfig.hooks is not None:
5414 for hook in optionsConfig.hooks:
5415 Config._addHook(xmlDom, sectionNode, hook)
5416
5417 @staticmethod
5418 - def _addPeers(xmlDom, parentNode, peersConfig):
5419 """
5420 Adds a <peers> configuration section as the next child of a parent.
5421
5422 We add groups of the following items, one list element per
5423 item::
5424
5425 localPeers //cb_config/peers/peer
5426 remotePeers //cb_config/peers/peer
5427
5428 The individual local and remote peer entries are added by
5429 L{_addLocalPeer} and L{_addRemotePeer}, respectively.
5430
5431 If C{peersConfig} is C{None}, then no container will be added.
5432
5433 @param xmlDom: DOM tree as from L{createOutputDom}.
5434 @param parentNode: Parent that the section should be appended to.
5435 @param peersConfig: Peers configuration section to be added to the document.
5436 """
5437 if peersConfig is not None:
5438 sectionNode = addContainerNode(xmlDom, parentNode, "peers")
5439 if peersConfig.localPeers is not None:
5440 for localPeer in peersConfig.localPeers:
5441 Config._addLocalPeer(xmlDom, sectionNode, localPeer)
5442 if peersConfig.remotePeers is not None:
5443 for remotePeer in peersConfig.remotePeers:
5444 Config._addRemotePeer(xmlDom, sectionNode, remotePeer)
5445
5446 @staticmethod
5448 """
5449 Adds a <collect> configuration section as the next child of a parent.
5450
5451 We add the following fields to the document::
5452
5453 targetDir //cb_config/collect/collect_dir
5454 collectMode //cb_config/collect/collect_mode
5455 archiveMode //cb_config/collect/archive_mode
5456 ignoreFile //cb_config/collect/ignore_file
5457
5458 We also add groups of the following items, one list element per
5459 item::
5460
5461 absoluteExcludePaths //cb_config/collect/exclude/abs_path
5462 excludePatterns //cb_config/collect/exclude/pattern
5463 collectFiles //cb_config/collect/file
5464 collectDirs //cb_config/collect/dir
5465
5466 The individual collect files are added by L{_addCollectFile} and
5467 individual collect directories are added by L{_addCollectDir}.
5468
5469 If C{collectConfig} is C{None}, then no container will be added.
5470
5471 @param xmlDom: DOM tree as from L{createOutputDom}.
5472 @param parentNode: Parent that the section should be appended to.
5473 @param collectConfig: Collect configuration section to be added to the document.
5474 """
5475 if collectConfig is not None:
5476 sectionNode = addContainerNode(xmlDom, parentNode, "collect")
5477 addStringNode(xmlDom, sectionNode, "collect_dir", collectConfig.targetDir)
5478 addStringNode(xmlDom, sectionNode, "collect_mode", collectConfig.collectMode)
5479 addStringNode(xmlDom, sectionNode, "archive_mode", collectConfig.archiveMode)
5480 addStringNode(xmlDom, sectionNode, "ignore_file", collectConfig.ignoreFile)
5481 if ((collectConfig.absoluteExcludePaths is not None and collectConfig.absoluteExcludePaths != []) or
5482 (collectConfig.excludePatterns is not None and collectConfig.excludePatterns != [])):
5483 excludeNode = addContainerNode(xmlDom, sectionNode, "exclude")
5484 if collectConfig.absoluteExcludePaths is not None:
5485 for absolutePath in collectConfig.absoluteExcludePaths:
5486 addStringNode(xmlDom, excludeNode, "abs_path", absolutePath)
5487 if collectConfig.excludePatterns is not None:
5488 for pattern in collectConfig.excludePatterns:
5489 addStringNode(xmlDom, excludeNode, "pattern", pattern)
5490 if collectConfig.collectFiles is not None:
5491 for collectFile in collectConfig.collectFiles:
5492 Config._addCollectFile(xmlDom, sectionNode, collectFile)
5493 if collectConfig.collectDirs is not None:
5494 for collectDir in collectConfig.collectDirs:
5495 Config._addCollectDir(xmlDom, sectionNode, collectDir)
5496
5497 @staticmethod
5498 - def _addStage(xmlDom, parentNode, stageConfig):
5499 """
5500 Adds a <stage> configuration section as the next child of a parent.
5501
5502 We add the following fields to the document::
5503
5504 targetDir //cb_config/stage/staging_dir
5505
5506 We also add groups of the following items, one list element per
5507 item::
5508
5509 localPeers //cb_config/stage/peer
5510 remotePeers //cb_config/stage/peer
5511
5512 The individual local and remote peer entries are added by
5513 L{_addLocalPeer} and L{_addRemotePeer}, respectively.
5514
5515 If C{stageConfig} is C{None}, then no container will be added.
5516
5517 @param xmlDom: DOM tree as from L{createOutputDom}.
5518 @param parentNode: Parent that the section should be appended to.
5519 @param stageConfig: Stage configuration section to be added to the document.
5520 """
5521 if stageConfig is not None:
5522 sectionNode = addContainerNode(xmlDom, parentNode, "stage")
5523 addStringNode(xmlDom, sectionNode, "staging_dir", stageConfig.targetDir)
5524 if stageConfig.localPeers is not None:
5525 for localPeer in stageConfig.localPeers:
5526 Config._addLocalPeer(xmlDom, sectionNode, localPeer)
5527 if stageConfig.remotePeers is not None:
5528 for remotePeer in stageConfig.remotePeers:
5529 Config._addRemotePeer(xmlDom, sectionNode, remotePeer)
5530
5531 @staticmethod
5532 - def _addStore(xmlDom, parentNode, storeConfig):
5533 """
5534 Adds a <store> configuration section as the next child of a parent.
5535
5536 We add the following fields to the document::
5537
5538 sourceDir //cb_config/store/source_dir
5539 mediaType //cb_config/store/media_type
5540 deviceType //cb_config/store/device_type
5541 devicePath //cb_config/store/target_device
5542 deviceScsiId //cb_config/store/target_scsi_id
5543 driveSpeed //cb_config/store/drive_speed
5544 checkData //cb_config/store/check_data
5545 checkMedia //cb_config/store/check_media
5546 warnMidnite //cb_config/store/warn_midnite
5547 noEject //cb_config/store/no_eject
5548 refreshMediaDelay //cb_config/store/refresh_media_delay
5549 ejectDelay //cb_config/store/eject_delay
5550
5551 Blanking behavior configuration is added by the L{_addBlankBehavior}
5552 method.
5553
5554 If C{storeConfig} is C{None}, then no container will be added.
5555
5556 @param xmlDom: DOM tree as from L{createOutputDom}.
5557 @param parentNode: Parent that the section should be appended to.
5558 @param storeConfig: Store configuration section to be added to the document.
5559 """
5560 if storeConfig is not None:
5561 sectionNode = addContainerNode(xmlDom, parentNode, "store")
5562 addStringNode(xmlDom, sectionNode, "source_dir", storeConfig.sourceDir)
5563 addStringNode(xmlDom, sectionNode, "media_type", storeConfig.mediaType)
5564 addStringNode(xmlDom, sectionNode, "device_type", storeConfig.deviceType)
5565 addStringNode(xmlDom, sectionNode, "target_device", storeConfig.devicePath)
5566 addStringNode(xmlDom, sectionNode, "target_scsi_id", storeConfig.deviceScsiId)
5567 addIntegerNode(xmlDom, sectionNode, "drive_speed", storeConfig.driveSpeed)
5568 addBooleanNode(xmlDom, sectionNode, "check_data", storeConfig.checkData)
5569 addBooleanNode(xmlDom, sectionNode, "check_media", storeConfig.checkMedia)
5570 addBooleanNode(xmlDom, sectionNode, "warn_midnite", storeConfig.warnMidnite)
5571 addBooleanNode(xmlDom, sectionNode, "no_eject", storeConfig.noEject)
5572 addIntegerNode(xmlDom, sectionNode, "refresh_media_delay", storeConfig.refreshMediaDelay)
5573 addIntegerNode(xmlDom, sectionNode, "eject_delay", storeConfig.ejectDelay)
5574 Config._addBlankBehavior(xmlDom, sectionNode, storeConfig.blankBehavior)
5575
5576 @staticmethod
5577 - def _addPurge(xmlDom, parentNode, purgeConfig):
5578 """
5579 Adds a <purge> configuration section as the next child of a parent.
5580
5581 We add the following fields to the document::
5582
5583 purgeDirs //cb_config/purge/dir
5584
5585 The individual directory entries are added by L{_addPurgeDir}.
5586
5587 If C{purgeConfig} is C{None}, then no container will be added.
5588
5589 @param xmlDom: DOM tree as from L{createOutputDom}.
5590 @param parentNode: Parent that the section should be appended to.
5591 @param purgeConfig: Purge configuration section to be added to the document.
5592 """
5593 if purgeConfig is not None:
5594 sectionNode = addContainerNode(xmlDom, parentNode, "purge")
5595 if purgeConfig.purgeDirs is not None:
5596 for purgeDir in purgeConfig.purgeDirs:
5597 Config._addPurgeDir(xmlDom, sectionNode, purgeDir)
5598
5599 @staticmethod
5601 """
5602 Adds an extended action container as the next child of a parent.
5603
5604 We add the following fields to the document::
5605
5606 name action/name
5607 module action/module
5608 function action/function
5609 index action/index
5610 dependencies action/depends
5611
5612 Dependencies are added by the L{_addDependencies} method.
5613
5614 The <action> node itself is created as the next child of the parent node.
5615 This method only adds one action node. The parent must loop for each action
5616 in the C{ExtensionsConfig} object.
5617
5618 If C{action} is C{None}, this method call will be a no-op.
5619
5620 @param xmlDom: DOM tree as from L{createOutputDom}.
5621 @param parentNode: Parent that the section should be appended to.
5622 @param action: Purge directory to be added to the document.
5623 """
5624 if action is not None:
5625 sectionNode = addContainerNode(xmlDom, parentNode, "action")
5626 addStringNode(xmlDom, sectionNode, "name", action.name)
5627 addStringNode(xmlDom, sectionNode, "module", action.module)
5628 addStringNode(xmlDom, sectionNode, "function", action.function)
5629 addIntegerNode(xmlDom, sectionNode, "index", action.index)
5630 Config._addDependencies(xmlDom, sectionNode, action.dependencies)
5631
5632 @staticmethod
5634 """
5635 Adds a command override container as the next child of a parent.
5636
5637 We add the following fields to the document::
5638
5639 command override/command
5640 absolutePath override/abs_path
5641
5642 The <override> node itself is created as the next child of the parent
5643 node. This method only adds one override node. The parent must loop for
5644 each override in the C{OptionsConfig} object.
5645
5646 If C{override} is C{None}, this method call will be a no-op.
5647
5648 @param xmlDom: DOM tree as from L{createOutputDom}.
5649 @param parentNode: Parent that the section should be appended to.
5650 @param override: Command override to be added to the document.
5651 """
5652 if override is not None:
5653 sectionNode = addContainerNode(xmlDom, parentNode, "override")
5654 addStringNode(xmlDom, sectionNode, "command", override.command)
5655 addStringNode(xmlDom, sectionNode, "abs_path", override.absolutePath)
5656
5657 @staticmethod
5658 - def _addHook(xmlDom, parentNode, hook):
5659 """
5660 Adds an action hook container as the next child of a parent.
5661
5662 The behavior varies depending on the value of the C{before} and C{after}
5663 flags on the hook. If the C{before} flag is set, it's a pre-action hook,
5664 and we'll add the following fields::
5665
5666 action pre_action_hook/action
5667 command pre_action_hook/command
5668
5669 If the C{after} flag is set, it's a post-action hook, and we'll add the
5670 following fields::
5671
5672 action post_action_hook/action
5673 command post_action_hook/command
5674
5675 The <pre_action_hook> or <post_action_hook> node itself is created as the
5676 next child of the parent node. This method only adds one hook node. The
5677 parent must loop for each hook in the C{OptionsConfig} object.
5678
5679 If C{hook} is C{None}, this method call will be a no-op.
5680
5681 @param xmlDom: DOM tree as from L{createOutputDom}.
5682 @param parentNode: Parent that the section should be appended to.
5683 @param hook: Command hook to be added to the document.
5684 """
5685 if hook is not None:
5686 if hook.before:
5687 sectionNode = addContainerNode(xmlDom, parentNode, "pre_action_hook")
5688 else:
5689 sectionNode = addContainerNode(xmlDom, parentNode, "post_action_hook")
5690 addStringNode(xmlDom, sectionNode, "action", hook.action)
5691 addStringNode(xmlDom, sectionNode, "command", hook.command)
5692
5693 @staticmethod
5695 """
5696 Adds a collect file container as the next child of a parent.
5697
5698 We add the following fields to the document::
5699
5700 absolutePath dir/abs_path
5701 collectMode dir/collect_mode
5702 archiveMode dir/archive_mode
5703
5704 Note that for consistency with collect directory handling we'll only emit
5705 the preferred C{collect_mode} tag.
5706
5707 The <file> node itself is created as the next child of the parent node.
5708 This method only adds one collect file node. The parent must loop
5709 for each collect file in the C{CollectConfig} object.
5710
5711 If C{collectFile} is C{None}, this method call will be a no-op.
5712
5713 @param xmlDom: DOM tree as from L{createOutputDom}.
5714 @param parentNode: Parent that the section should be appended to.
5715 @param collectFile: Collect file to be added to the document.
5716 """
5717 if collectFile is not None:
5718 sectionNode = addContainerNode(xmlDom, parentNode, "file")
5719 addStringNode(xmlDom, sectionNode, "abs_path", collectFile.absolutePath)
5720 addStringNode(xmlDom, sectionNode, "collect_mode", collectFile.collectMode)
5721 addStringNode(xmlDom, sectionNode, "archive_mode", collectFile.archiveMode)
5722
5723 @staticmethod
5725 """
5726 Adds a collect directory container as the next child of a parent.
5727
5728 We add the following fields to the document::
5729
5730 absolutePath dir/abs_path
5731 collectMode dir/collect_mode
5732 archiveMode dir/archive_mode
5733 ignoreFile dir/ignore_file
5734 linkDepth dir/link_depth
5735 dereference dir/dereference
5736 recursionLevel dir/recursion_level
5737
5738 Note that an original XML document might have listed the collect mode
5739 using the C{mode} tag, since we accept both C{collect_mode} and C{mode}.
5740 However, here we'll only emit the preferred C{collect_mode} tag.
5741
5742 We also add groups of the following items, one list element per item::
5743
5744 absoluteExcludePaths dir/exclude/abs_path
5745 relativeExcludePaths dir/exclude/rel_path
5746 excludePatterns dir/exclude/pattern
5747
5748 The <dir> node itself is created as the next child of the parent node.
5749 This method only adds one collect directory node. The parent must loop
5750 for each collect directory in the C{CollectConfig} object.
5751
5752 If C{collectDir} is C{None}, this method call will be a no-op.
5753
5754 @param xmlDom: DOM tree as from L{createOutputDom}.
5755 @param parentNode: Parent that the section should be appended to.
5756 @param collectDir: Collect directory to be added to the document.
5757 """
5758 if collectDir is not None:
5759 sectionNode = addContainerNode(xmlDom, parentNode, "dir")
5760 addStringNode(xmlDom, sectionNode, "abs_path", collectDir.absolutePath)
5761 addStringNode(xmlDom, sectionNode, "collect_mode", collectDir.collectMode)
5762 addStringNode(xmlDom, sectionNode, "archive_mode", collectDir.archiveMode)
5763 addStringNode(xmlDom, sectionNode, "ignore_file", collectDir.ignoreFile)
5764 addIntegerNode(xmlDom, sectionNode, "link_depth", collectDir.linkDepth)
5765 addBooleanNode(xmlDom, sectionNode, "dereference", collectDir.dereference)
5766 addIntegerNode(xmlDom, sectionNode, "recursion_level", collectDir.recursionLevel)
5767 if ((collectDir.absoluteExcludePaths is not None and collectDir.absoluteExcludePaths != []) or
5768 (collectDir.relativeExcludePaths is not None and collectDir.relativeExcludePaths != []) or
5769 (collectDir.excludePatterns is not None and collectDir.excludePatterns != [])):
5770 excludeNode = addContainerNode(xmlDom, sectionNode, "exclude")
5771 if collectDir.absoluteExcludePaths is not None:
5772 for absolutePath in collectDir.absoluteExcludePaths:
5773 addStringNode(xmlDom, excludeNode, "abs_path", absolutePath)
5774 if collectDir.relativeExcludePaths is not None:
5775 for relativePath in collectDir.relativeExcludePaths:
5776 addStringNode(xmlDom, excludeNode, "rel_path", relativePath)
5777 if collectDir.excludePatterns is not None:
5778 for pattern in collectDir.excludePatterns:
5779 addStringNode(xmlDom, excludeNode, "pattern", pattern)
5780
5781 @staticmethod
5783 """
5784 Adds a local peer container as the next child of a parent.
5785
5786 We add the following fields to the document::
5787
5788 name peer/name
5789 collectDir peer/collect_dir
5790 ignoreFailureMode peer/ignore_failures
5791
5792 Additionally, C{peer/type} is filled in with C{"local"}, since this is a
5793 local peer.
5794
5795 The <peer> node itself is created as the next child of the parent node.
5796 This method only adds one peer node. The parent must loop for each peer
5797 in the C{StageConfig} object.
5798
5799 If C{localPeer} is C{None}, this method call will be a no-op.
5800
5801 @param xmlDom: DOM tree as from L{createOutputDom}.
5802 @param parentNode: Parent that the section should be appended to.
5803 @param localPeer: Purge directory to be added to the document.
5804 """
5805 if localPeer is not None:
5806 sectionNode = addContainerNode(xmlDom, parentNode, "peer")
5807 addStringNode(xmlDom, sectionNode, "name", localPeer.name)
5808 addStringNode(xmlDom, sectionNode, "type", "local")
5809 addStringNode(xmlDom, sectionNode, "collect_dir", localPeer.collectDir)
5810 addStringNode(xmlDom, sectionNode, "ignore_failures", localPeer.ignoreFailureMode)
5811
5812 @staticmethod
5814 """
5815 Adds a remote peer container as the next child of a parent.
5816
5817 We add the following fields to the document::
5818
5819 name peer/name
5820 collectDir peer/collect_dir
5821 remoteUser peer/backup_user
5822 rcpCommand peer/rcp_command
5823 rcpCommand peer/rcp_command
5824 rshCommand peer/rsh_command
5825 cbackCommand peer/cback_command
5826 ignoreFailureMode peer/ignore_failures
5827 managed peer/managed
5828 managedActions peer/managed_actions
5829
5830 Additionally, C{peer/type} is filled in with C{"remote"}, since this is a
5831 remote peer.
5832
5833 The <peer> node itself is created as the next child of the parent node.
5834 This method only adds one peer node. The parent must loop for each peer
5835 in the C{StageConfig} object.
5836
5837 If C{remotePeer} is C{None}, this method call will be a no-op.
5838
5839 @param xmlDom: DOM tree as from L{createOutputDom}.
5840 @param parentNode: Parent that the section should be appended to.
5841 @param remotePeer: Purge directory to be added to the document.
5842 """
5843 if remotePeer is not None:
5844 sectionNode = addContainerNode(xmlDom, parentNode, "peer")
5845 addStringNode(xmlDom, sectionNode, "name", remotePeer.name)
5846 addStringNode(xmlDom, sectionNode, "type", "remote")
5847 addStringNode(xmlDom, sectionNode, "collect_dir", remotePeer.collectDir)
5848 addStringNode(xmlDom, sectionNode, "backup_user", remotePeer.remoteUser)
5849 addStringNode(xmlDom, sectionNode, "rcp_command", remotePeer.rcpCommand)
5850 addStringNode(xmlDom, sectionNode, "rsh_command", remotePeer.rshCommand)
5851 addStringNode(xmlDom, sectionNode, "cback_command", remotePeer.cbackCommand)
5852 addStringNode(xmlDom, sectionNode, "ignore_failures", remotePeer.ignoreFailureMode)
5853 addBooleanNode(xmlDom, sectionNode, "managed", remotePeer.managed)
5854 managedActions = Config._buildCommaSeparatedString(remotePeer.managedActions)
5855 addStringNode(xmlDom, sectionNode, "managed_actions", managedActions)
5856
5857 @staticmethod
5859 """
5860 Adds a purge directory container as the next child of a parent.
5861
5862 We add the following fields to the document::
5863
5864 absolutePath dir/abs_path
5865 retainDays dir/retain_days
5866
5867 The <dir> node itself is created as the next child of the parent node.
5868 This method only adds one purge directory node. The parent must loop for
5869 each purge directory in the C{PurgeConfig} object.
5870
5871 If C{purgeDir} is C{None}, this method call will be a no-op.
5872
5873 @param xmlDom: DOM tree as from L{createOutputDom}.
5874 @param parentNode: Parent that the section should be appended to.
5875 @param purgeDir: Purge directory to be added to the document.
5876 """
5877 if purgeDir is not None:
5878 sectionNode = addContainerNode(xmlDom, parentNode, "dir")
5879 addStringNode(xmlDom, sectionNode, "abs_path", purgeDir.absolutePath)
5880 addIntegerNode(xmlDom, sectionNode, "retain_days", purgeDir.retainDays)
5881
5882 @staticmethod
5884 """
5885 Adds a extended action dependencies to parent node.
5886
5887 We add the following fields to the document::
5888
5889 runBefore depends/run_before
5890 runAfter depends/run_after
5891
5892 If C{dependencies} is C{None}, this method call will be a no-op.
5893
5894 @param xmlDom: DOM tree as from L{createOutputDom}.
5895 @param parentNode: Parent that the section should be appended to.
5896 @param dependencies: C{ActionDependencies} object to be added to the document
5897 """
5898 if dependencies is not None:
5899 sectionNode = addContainerNode(xmlDom, parentNode, "depends")
5900 runBefore = Config._buildCommaSeparatedString(dependencies.beforeList)
5901 runAfter = Config._buildCommaSeparatedString(dependencies.afterList)
5902 addStringNode(xmlDom, sectionNode, "run_before", runBefore)
5903 addStringNode(xmlDom, sectionNode, "run_after", runAfter)
5904
5905 @staticmethod
5907 """
5908 Creates a comma-separated string from a list of values.
5909
5910 As a special case, if C{valueList} is C{None}, then C{None} will be
5911 returned.
5912
5913 @param valueList: List of values to be placed into a string
5914
5915 @return: Values from valueList as a comma-separated string.
5916 """
5917 if valueList is None:
5918 return None
5919 return ",".join(valueList)
5920
5921 @staticmethod
5923 """
5924 Adds a blanking behavior container as the next child of a parent.
5925
5926 We add the following fields to the document::
5927
5928 blankMode blank_behavior/mode
5929 blankFactor blank_behavior/factor
5930
5931 The <blank_behavior> node itself is created as the next child of the
5932 parent node.
5933
5934 If C{blankBehavior} is C{None}, this method call will be a no-op.
5935
5936 @param xmlDom: DOM tree as from L{createOutputDom}.
5937 @param parentNode: Parent that the section should be appended to.
5938 @param blankBehavior: Blanking behavior to be added to the document.
5939 """
5940 if blankBehavior is not None:
5941 sectionNode = addContainerNode(xmlDom, parentNode, "blank_behavior")
5942 addStringNode(xmlDom, sectionNode, "mode", blankBehavior.blankMode)
5943 addStringNode(xmlDom, sectionNode, "factor", blankBehavior.blankFactor)
5944
5945
5946
5947
5948
5949
5951 """
5952 Validates configuration contents per rules discussed in module
5953 documentation.
5954
5955 This is the second pass at validation. It ensures that any filled-in
5956 section contains valid data. Any sections which is not set to C{None} is
5957 validated per the rules for that section, laid out in the module
5958 documentation (above).
5959
5960 @raise ValueError: If configuration is invalid.
5961 """
5962 self._validateReference()
5963 self._validateExtensions()
5964 self._validateOptions()
5965 self._validatePeers()
5966 self._validateCollect()
5967 self._validateStage()
5968 self._validateStore()
5969 self._validatePurge()
5970
5972 """
5973 Validates reference configuration.
5974 There are currently no reference-related validations.
5975 @raise ValueError: If reference configuration is invalid.
5976 """
5977 pass
5978
5980 """
5981 Validates extensions configuration.
5982
5983 The list of actions may be either C{None} or an empty list C{[]} if
5984 desired. Each extended action must include a name, a module, and a
5985 function.
5986
5987 Then, if the order mode is None or "index", an index is required; and if
5988 the order mode is "dependency", dependency information is required.
5989
5990 @raise ValueError: If reference configuration is invalid.
5991 """
5992 if self.extensions is not None:
5993 if self.extensions.actions is not None:
5994 names = []
5995 for action in self.extensions.actions:
5996 if action.name is None:
5997 raise ValueError("Each extended action must set a name.")
5998 names.append(action.name)
5999 if action.module is None:
6000 raise ValueError("Each extended action must set a module.")
6001 if action.function is None:
6002 raise ValueError("Each extended action must set a function.")
6003 if self.extensions.orderMode is None or self.extensions.orderMode == "index":
6004 if action.index is None:
6005 raise ValueError("Each extended action must set an index, based on order mode.")
6006 elif self.extensions.orderMode == "dependency":
6007 if action.dependencies is None:
6008 raise ValueError("Each extended action must set dependency information, based on order mode.")
6009 checkUnique("Duplicate extension names exist:", names)
6010
6012 """
6013 Validates options configuration.
6014
6015 All fields must be filled in except the rsh command. The rcp and rsh
6016 commands are used as default values for all remote peers. Remote peers
6017 can also rely on the backup user as the default remote user name if they
6018 choose.
6019
6020 @raise ValueError: If reference configuration is invalid.
6021 """
6022 if self.options is not None:
6023 if self.options.startingDay is None:
6024 raise ValueError("Options section starting day must be filled in.")
6025 if self.options.workingDir is None:
6026 raise ValueError("Options section working directory must be filled in.")
6027 if self.options.backupUser is None:
6028 raise ValueError("Options section backup user must be filled in.")
6029 if self.options.backupGroup is None:
6030 raise ValueError("Options section backup group must be filled in.")
6031 if self.options.rcpCommand is None:
6032 raise ValueError("Options section remote copy command must be filled in.")
6033
6041
6043 """
6044 Validates collect configuration.
6045
6046 The target directory must be filled in. The collect mode, archive mode,
6047 ignore file, and recursion level are all optional. The list of absolute
6048 paths to exclude and patterns to exclude may be either C{None} or an
6049 empty list C{[]} if desired.
6050
6051 Each collect directory entry must contain an absolute path to collect,
6052 and then must either be able to take collect mode, archive mode and
6053 ignore file configuration from the parent C{CollectConfig} object, or
6054 must set each value on its own. The list of absolute paths to exclude,
6055 relative paths to exclude and patterns to exclude may be either C{None}
6056 or an empty list C{[]} if desired. Any list of absolute paths to exclude
6057 or patterns to exclude will be combined with the same list in the
6058 C{CollectConfig} object to make the complete list for a given directory.
6059
6060 @raise ValueError: If collect configuration is invalid.
6061 """
6062 if self.collect is not None:
6063 if self.collect.targetDir is None:
6064 raise ValueError("Collect section target directory must be filled in.")
6065 if self.collect.collectFiles is not None:
6066 for collectFile in self.collect.collectFiles:
6067 if collectFile.absolutePath is None:
6068 raise ValueError("Each collect file must set an absolute path.")
6069 if self.collect.collectMode is None and collectFile.collectMode is None:
6070 raise ValueError("Collect mode must either be set in parent collect section or individual collect file.")
6071 if self.collect.archiveMode is None and collectFile.archiveMode is None:
6072 raise ValueError("Archive mode must either be set in parent collect section or individual collect file.")
6073 if self.collect.collectDirs is not None:
6074 for collectDir in self.collect.collectDirs:
6075 if collectDir.absolutePath is None:
6076 raise ValueError("Each collect directory must set an absolute path.")
6077 if self.collect.collectMode is None and collectDir.collectMode is None:
6078 raise ValueError("Collect mode must either be set in parent collect section or individual collect directory.")
6079 if self.collect.archiveMode is None and collectDir.archiveMode is None:
6080 raise ValueError("Archive mode must either be set in parent collect section or individual collect directory.")
6081 if self.collect.ignoreFile is None and collectDir.ignoreFile is None:
6082 raise ValueError("Ignore file must either be set in parent collect section or individual collect directory.")
6083 if (collectDir.linkDepth is None or collectDir.linkDepth < 1) and collectDir.dereference:
6084 raise ValueError("Dereference flag is only valid when a non-zero link depth is in use.")
6085
6087 """
6088 Validates stage configuration.
6089
6090 The target directory must be filled in, and the peers are
6091 also validated.
6092
6093 Peers are only required in this section if the peers configuration
6094 section is not filled in. However, if any peers are filled in
6095 here, they override the peers configuration and must meet the
6096 validation criteria in L{_validatePeerList}.
6097
6098 @raise ValueError: If stage configuration is invalid.
6099 """
6100 if self.stage is not None:
6101 if self.stage.targetDir is None:
6102 raise ValueError("Stage section target directory must be filled in.")
6103 if self.peers is None:
6104
6105 self._validatePeerList(self.stage.localPeers, self.stage.remotePeers)
6106 else:
6107
6108
6109 if self.stage.hasPeers():
6110 self._validatePeerList(self.stage.localPeers, self.stage.remotePeers)
6111
6113 """
6114 Validates store configuration.
6115
6116 The device type, drive speed, and blanking behavior are optional. All
6117 other values are required. Missing booleans will be set to defaults.
6118
6119 If blanking behavior is provided, then both a blanking mode and a
6120 blanking factor are required.
6121
6122 The image writer functionality in the C{writer} module is supposed to be
6123 able to handle a device speed of C{None}.
6124
6125 Any caller which needs a "real" (non-C{None}) value for the device type
6126 can use C{DEFAULT_DEVICE_TYPE}, which is guaranteed to be sensible.
6127
6128 This is also where we make sure that the media type -- which is already a
6129 valid type -- matches up properly with the device type.
6130
6131 @raise ValueError: If store configuration is invalid.
6132 """
6133 if self.store is not None:
6134 if self.store.sourceDir is None:
6135 raise ValueError("Store section source directory must be filled in.")
6136 if self.store.mediaType is None:
6137 raise ValueError("Store section media type must be filled in.")
6138 if self.store.devicePath is None:
6139 raise ValueError("Store section device path must be filled in.")
6140 if self.store.deviceType == None or self.store.deviceType == "cdwriter":
6141 if self.store.mediaType not in VALID_CD_MEDIA_TYPES:
6142 raise ValueError("Media type must match device type.")
6143 elif self.store.deviceType == "dvdwriter":
6144 if self.store.mediaType not in VALID_DVD_MEDIA_TYPES:
6145 raise ValueError("Media type must match device type.")
6146 if self.store.blankBehavior is not None:
6147 if self.store.blankBehavior.blankMode is None and self.store.blankBehavior.blankFactor is None:
6148 raise ValueError("If blanking behavior is provided, all values must be filled in.")
6149
6151 """
6152 Validates purge configuration.
6153
6154 The list of purge directories may be either C{None} or an empty list
6155 C{[]} if desired. All purge directories must contain a path and a retain
6156 days value.
6157
6158 @raise ValueError: If purge configuration is invalid.
6159 """
6160 if self.purge is not None:
6161 if self.purge.purgeDirs is not None:
6162 for purgeDir in self.purge.purgeDirs:
6163 if purgeDir.absolutePath is None:
6164 raise ValueError("Each purge directory must set an absolute path.")
6165 if purgeDir.retainDays is None:
6166 raise ValueError("Each purge directory must set a retain days value.")
6167
6169 """
6170 Validates the set of local and remote peers.
6171
6172 Local peers must be completely filled in, including both name and collect
6173 directory. Remote peers must also fill in the name and collect
6174 directory, but can leave the remote user and rcp command unset. In this
6175 case, the remote user is assumed to match the backup user from the
6176 options section and rcp command is taken directly from the options
6177 section.
6178
6179 @param localPeers: List of local peers
6180 @param remotePeers: List of remote peers
6181
6182 @raise ValueError: If stage configuration is invalid.
6183 """
6184 if localPeers is None and remotePeers is None:
6185 raise ValueError("Peer list must contain at least one backup peer.")
6186 if localPeers is None and remotePeers is not None:
6187 if len(remotePeers) < 1:
6188 raise ValueError("Peer list must contain at least one backup peer.")
6189 elif localPeers is not None and remotePeers is None:
6190 if len(localPeers) < 1:
6191 raise ValueError("Peer list must contain at least one backup peer.")
6192 elif localPeers is not None and remotePeers is not None:
6193 if len(localPeers) + len(remotePeers) < 1:
6194 raise ValueError("Peer list must contain at least one backup peer.")
6195 names = []
6196 if localPeers is not None:
6197 for localPeer in localPeers:
6198 if localPeer.name is None:
6199 raise ValueError("Local peers must set a name.")
6200 names.append(localPeer.name)
6201 if localPeer.collectDir is None:
6202 raise ValueError("Local peers must set a collect directory.")
6203 if remotePeers is not None:
6204 for remotePeer in remotePeers:
6205 if remotePeer.name is None:
6206 raise ValueError("Remote peers must set a name.")
6207 names.append(remotePeer.name)
6208 if remotePeer.collectDir is None:
6209 raise ValueError("Remote peers must set a collect directory.")
6210 if (self.options is None or self.options.backupUser is None) and remotePeer.remoteUser is None:
6211 raise ValueError("Remote user must either be set in options section or individual remote peer.")
6212 if (self.options is None or self.options.rcpCommand is None) and remotePeer.rcpCommand is None:
6213 raise ValueError("Remote copy command must either be set in options section or individual remote peer.")
6214 if remotePeer.managed:
6215 if (self.options is None or self.options.rshCommand is None) and remotePeer.rshCommand is None:
6216 raise ValueError("Remote shell command must either be set in options section or individual remote peer.")
6217 if (self.options is None or self.options.cbackCommand is None) and remotePeer.cbackCommand is None:
6218 raise ValueError("Remote cback command must either be set in options section or individual remote peer.")
6219 if ((self.options is None or self.options.managedActions is None or len(self.options.managedActions) < 1)
6220 and (remotePeer.managedActions is None or len(remotePeer.managedActions) < 1)):
6221 raise ValueError("Managed actions list must be set in options section or individual remote peer.")
6222 checkUnique("Duplicate peer names exist:", names)
6223
6230 """
6231 Read a byte size value from an XML document.
6232
6233 A byte size value is an interpreted string value. If the string value
6234 ends with "MB" or "GB", then the string before that is interpreted as
6235 megabytes or gigabytes. Otherwise, it is intepreted as bytes.
6236
6237 @param parent: Parent node to search beneath.
6238 @param name: Name of node to search for.
6239
6240 @return: ByteQuantity parsed from XML document
6241 """
6242 data = readString(parent, name)
6243 if data is None:
6244 return None
6245 data = data.strip()
6246 if data.endswith("KB"):
6247 quantity = data[0:data.rfind("KB")].strip()
6248 units = UNIT_KBYTES
6249 elif data.endswith("MB"):
6250 quantity = data[0:data.rfind("MB")].strip()
6251 units = UNIT_MBYTES
6252 elif data.endswith("GB"):
6253 quantity = data[0:data.rfind("GB")].strip()
6254 units = UNIT_GBYTES
6255 else:
6256 quantity = data.strip()
6257 units = UNIT_BYTES
6258 return ByteQuantity(quantity, units)
6259
6261 """
6262 Adds a text node as the next child of a parent, to contain a byte size.
6263
6264 If the C{byteQuantity} is None, then the node will be created, but will
6265 be empty (i.e. will contain no text node child).
6266
6267 The size in bytes will be normalized. If it is larger than 1.0 GB, it will
6268 be shown in GB ("1.0 GB"). If it is larger than 1.0 MB ("1.0 MB"), it will
6269 be shown in MB. Otherwise, it will be shown in bytes ("423413").
6270
6271 @param xmlDom: DOM tree as from C{impl.createDocument()}.
6272 @param parentNode: Parent node to create child for.
6273 @param nodeName: Name of the new container node.
6274 @param byteQuantity: ByteQuantity object to put into the XML document
6275
6276 @return: Reference to the newly-created node.
6277 """
6278 if byteQuantity is None:
6279 byteString = None
6280 elif byteQuantity.units == UNIT_KBYTES:
6281 byteString = "%s KB" % byteQuantity.quantity
6282 elif byteQuantity.units == UNIT_MBYTES:
6283 byteString = "%s MB" % byteQuantity.quantity
6284 elif byteQuantity.units == UNIT_GBYTES:
6285 byteString = "%s GB" % byteQuantity.quantity
6286 else:
6287 byteString = byteQuantity.quantity
6288 return addStringNode(xmlDom, parentNode, nodeName, byteString)
6289