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