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
5022
5024 """
5025 Reads a list of C{ActionHook} objects from immediately beneath the parent.
5026
5027 We read the following individual fields::
5028
5029 action action
5030 command command
5031
5032 @param parentNode: Parent node to search beneath.
5033
5034 @return: List of C{ActionHook} objects or C{None} if none are found.
5035 @raise ValueError: If some filled-in value is invalid.
5036 """
5037 lst = []
5038 for entry in readChildren(parentNode, "pre_action_hook"):
5039 if isElement(entry):
5040 hook = PreActionHook()
5041 hook.action = readString(entry, "action")
5042 hook.command = readString(entry, "command")
5043 lst.append(hook)
5044 for entry in readChildren(parentNode, "post_action_hook"):
5045 if isElement(entry):
5046 hook = PostActionHook()
5047 hook.action = readString(entry, "action")
5048 hook.command = readString(entry, "command")
5049 lst.append(hook)
5050 if lst == []:
5051 lst = None
5052 return lst
5053
5054 @staticmethod
5056 """
5057 Reads a list of C{CollectFile} objects from immediately beneath the parent.
5058
5059 We read the following individual fields::
5060
5061 absolutePath abs_path
5062 collectMode mode I{or} collect_mode
5063 archiveMode archive_mode
5064
5065 The collect mode is a special case. Just a C{mode} tag is accepted, but
5066 we prefer C{collect_mode} for consistency with the rest of the config
5067 file and to avoid confusion with the archive mode. If both are provided,
5068 only C{mode} will be used.
5069
5070 @param parentNode: Parent node to search beneath.
5071
5072 @return: List of C{CollectFile} objects or C{None} if none are found.
5073 @raise ValueError: If some filled-in value is invalid.
5074 """
5075 lst = []
5076 for entry in readChildren(parentNode, "file"):
5077 if isElement(entry):
5078 cfile = CollectFile()
5079 cfile.absolutePath = readString(entry, "abs_path")
5080 cfile.collectMode = readString(entry, "mode")
5081 if cfile.collectMode is None:
5082 cfile.collectMode = readString(entry, "collect_mode")
5083 cfile.archiveMode = readString(entry, "archive_mode")
5084 lst.append(cfile)
5085 if lst == []:
5086 lst = None
5087 return lst
5088
5089 @staticmethod
5091 """
5092 Reads a list of C{CollectDir} objects from immediately beneath the parent.
5093
5094 We read the following individual fields::
5095
5096 absolutePath abs_path
5097 collectMode mode I{or} collect_mode
5098 archiveMode archive_mode
5099 ignoreFile ignore_file
5100 linkDepth link_depth
5101 dereference dereference
5102 recursionLevel recursion_level
5103
5104 The collect mode is a special case. Just a C{mode} tag is accepted for
5105 backwards compatibility, but we prefer C{collect_mode} for consistency
5106 with the rest of the config file and to avoid confusion with the archive
5107 mode. If both are provided, only C{mode} will be used.
5108
5109 We also read groups of the following items, one list element per
5110 item::
5111
5112 absoluteExcludePaths exclude/abs_path
5113 relativeExcludePaths exclude/rel_path
5114 excludePatterns exclude/pattern
5115
5116 The exclusions are parsed by L{_parseExclusions}.
5117
5118 @param parentNode: Parent node to search beneath.
5119
5120 @return: List of C{CollectDir} objects or C{None} if none are found.
5121 @raise ValueError: If some filled-in value is invalid.
5122 """
5123 lst = []
5124 for entry in readChildren(parentNode, "dir"):
5125 if isElement(entry):
5126 cdir = CollectDir()
5127 cdir.absolutePath = readString(entry, "abs_path")
5128 cdir.collectMode = readString(entry, "mode")
5129 if cdir.collectMode is None:
5130 cdir.collectMode = readString(entry, "collect_mode")
5131 cdir.archiveMode = readString(entry, "archive_mode")
5132 cdir.ignoreFile = readString(entry, "ignore_file")
5133 cdir.linkDepth = readInteger(entry, "link_depth")
5134 cdir.dereference = readBoolean(entry, "dereference")
5135 cdir.recursionLevel = readInteger(entry, "recursion_level")
5136 (cdir.absoluteExcludePaths, cdir.relativeExcludePaths, cdir.excludePatterns) = Config._parseExclusions(entry)
5137 lst.append(cdir)
5138 if lst == []:
5139 lst = None
5140 return lst
5141
5142 @staticmethod
5144 """
5145 Reads a list of C{PurgeDir} objects from immediately beneath the parent.
5146
5147 We read the following individual fields::
5148
5149 absolutePath <baseExpr>/abs_path
5150 retainDays <baseExpr>/retain_days
5151
5152 @param parentNode: Parent node to search beneath.
5153
5154 @return: List of C{PurgeDir} objects or C{None} if none are found.
5155 @raise ValueError: If the data at the location can't be read
5156 """
5157 lst = []
5158 for entry in readChildren(parentNode, "dir"):
5159 if isElement(entry):
5160 cdir = PurgeDir()
5161 cdir.absolutePath = readString(entry, "abs_path")
5162 cdir.retainDays = readInteger(entry, "retain_days")
5163 lst.append(cdir)
5164 if lst == []:
5165 lst = None
5166 return lst
5167
5168 @staticmethod
5170 """
5171 Reads remote and local peer data from immediately beneath the parent.
5172
5173 We read the following individual fields for both remote
5174 and local peers::
5175
5176 name name
5177 collectDir collect_dir
5178
5179 We also read the following individual fields for remote peers
5180 only::
5181
5182 remoteUser backup_user
5183 rcpCommand rcp_command
5184 rshCommand rsh_command
5185 cbackCommand cback_command
5186 managed managed
5187 managedActions managed_actions
5188
5189 Additionally, the value in the C{type} field is used to determine whether
5190 this entry is a remote peer. If the type is C{"remote"}, it's a remote
5191 peer, and if the type is C{"local"}, it's a remote peer.
5192
5193 If there are none of one type of peer (i.e. no local peers) then C{None}
5194 will be returned for that item in the tuple.
5195
5196 @param parentNode: Parent node to search beneath.
5197
5198 @return: Tuple of (local, remote) peer lists.
5199 @raise ValueError: If the data at the location can't be read
5200 """
5201 localPeers = []
5202 remotePeers = []
5203 for entry in readChildren(parentNode, "peer"):
5204 if isElement(entry):
5205 peerType = readString(entry, "type")
5206 if peerType == "local":
5207 localPeer = LocalPeer()
5208 localPeer.name = readString(entry, "name")
5209 localPeer.collectDir = readString(entry, "collect_dir")
5210 localPeer.ignoreFailureMode = readString(entry, "ignore_failures")
5211 localPeers.append(localPeer)
5212 elif peerType == "remote":
5213 remotePeer = RemotePeer()
5214 remotePeer.name = readString(entry, "name")
5215 remotePeer.collectDir = readString(entry, "collect_dir")
5216 remotePeer.remoteUser = readString(entry, "backup_user")
5217 remotePeer.rcpCommand = readString(entry, "rcp_command")
5218 remotePeer.rshCommand = readString(entry, "rsh_command")
5219 remotePeer.cbackCommand = readString(entry, "cback_command")
5220 remotePeer.ignoreFailureMode = readString(entry, "ignore_failures")
5221 remotePeer.managed = readBoolean(entry, "managed")
5222 managedActions = readString(entry, "managed_actions")
5223 remotePeer.managedActions = parseCommaSeparatedString(managedActions)
5224 remotePeers.append(remotePeer)
5225 if localPeers == []:
5226 localPeers = None
5227 if remotePeers == []:
5228 remotePeers = None
5229 return (localPeers, remotePeers)
5230
5231 @staticmethod
5233 """
5234 Reads extended action dependency information from a parent node.
5235
5236 We read the following individual fields::
5237
5238 runBefore depends/run_before
5239 runAfter depends/run_after
5240
5241 Each of these fields is a comma-separated list of action names.
5242
5243 The result is placed into an C{ActionDependencies} object.
5244
5245 If the dependencies parent node does not exist, C{None} will be returned.
5246 Otherwise, an C{ActionDependencies} object will always be created, even
5247 if it does not contain any actual dependencies in it.
5248
5249 @param parentNode: Parent node to search beneath.
5250
5251 @return: C{ActionDependencies} object or C{None}.
5252 @raise ValueError: If the data at the location can't be read
5253 """
5254 sectionNode = readFirstChild(parentNode, "depends")
5255 if sectionNode is None:
5256 return None
5257 else:
5258 runBefore = readString(sectionNode, "run_before")
5259 runAfter = readString(sectionNode, "run_after")
5260 beforeList = parseCommaSeparatedString(runBefore)
5261 afterList = parseCommaSeparatedString(runAfter)
5262 return ActionDependencies(beforeList, afterList)
5263
5264 @staticmethod
5266 """
5267 Reads a single C{BlankBehavior} object from immediately beneath the parent.
5268
5269 We read the following individual fields::
5270
5271 blankMode blank_behavior/mode
5272 blankFactor blank_behavior/factor
5273
5274 @param parentNode: Parent node to search beneath.
5275
5276 @return: C{BlankBehavior} object or C{None} if none if the section is not found
5277 @raise ValueError: If some filled-in value is invalid.
5278 """
5279 blankBehavior = None
5280 sectionNode = readFirstChild(parentNode, "blank_behavior")
5281 if sectionNode is not None:
5282 blankBehavior = BlankBehavior()
5283 blankBehavior.blankMode = readString(sectionNode, "mode")
5284 blankBehavior.blankFactor = readString(sectionNode, "factor")
5285 return blankBehavior
5286
5287
5288
5289
5290
5291
5293 """
5294 Internal method to extract configuration into an XML string.
5295
5296 This method assumes that the internal L{validate} method has been called
5297 prior to extracting the XML, if the caller cares. No validation will be
5298 done internally.
5299
5300 As a general rule, fields that are set to C{None} will be extracted into
5301 the document as empty tags. The same goes for container tags that are
5302 filled based on lists - if the list is empty or C{None}, the container
5303 tag will be empty.
5304 """
5305 (xmlDom, parentNode) = createOutputDom()
5306 Config._addReference(xmlDom, parentNode, self.reference)
5307 Config._addExtensions(xmlDom, parentNode, self.extensions)
5308 Config._addOptions(xmlDom, parentNode, self.options)
5309 Config._addPeers(xmlDom, parentNode, self.peers)
5310 Config._addCollect(xmlDom, parentNode, self.collect)
5311 Config._addStage(xmlDom, parentNode, self.stage)
5312 Config._addStore(xmlDom, parentNode, self.store)
5313 Config._addPurge(xmlDom, parentNode, self.purge)
5314 xmlData = serializeDom(xmlDom)
5315 xmlDom.unlink()
5316 return xmlData
5317
5318 @staticmethod
5320 """
5321 Adds a <reference> configuration section as the next child of a parent.
5322
5323 We add the following fields to the document::
5324
5325 author //cb_config/reference/author
5326 revision //cb_config/reference/revision
5327 description //cb_config/reference/description
5328 generator //cb_config/reference/generator
5329
5330 If C{referenceConfig} is C{None}, then no container will be added.
5331
5332 @param xmlDom: DOM tree as from L{createOutputDom}.
5333 @param parentNode: Parent that the section should be appended to.
5334 @param referenceConfig: Reference configuration section to be added to the document.
5335 """
5336 if referenceConfig is not None:
5337 sectionNode = addContainerNode(xmlDom, parentNode, "reference")
5338 addStringNode(xmlDom, sectionNode, "author", referenceConfig.author)
5339 addStringNode(xmlDom, sectionNode, "revision", referenceConfig.revision)
5340 addStringNode(xmlDom, sectionNode, "description", referenceConfig.description)
5341 addStringNode(xmlDom, sectionNode, "generator", referenceConfig.generator)
5342
5343 @staticmethod
5345 """
5346 Adds an <extensions> configuration section as the next child of a parent.
5347
5348 We add the following fields to the document::
5349
5350 order_mode //cb_config/extensions/order_mode
5351
5352 We also add groups of the following items, one list element per item::
5353
5354 actions //cb_config/extensions/action
5355
5356 The extended action entries are added by L{_addExtendedAction}.
5357
5358 If C{extensionsConfig} is C{None}, then no container will be added.
5359
5360 @param xmlDom: DOM tree as from L{createOutputDom}.
5361 @param parentNode: Parent that the section should be appended to.
5362 @param extensionsConfig: Extensions configuration section to be added to the document.
5363 """
5364 if extensionsConfig is not None:
5365 sectionNode = addContainerNode(xmlDom, parentNode, "extensions")
5366 addStringNode(xmlDom, sectionNode, "order_mode", extensionsConfig.orderMode)
5367 if extensionsConfig.actions is not None:
5368 for action in extensionsConfig.actions:
5369 Config._addExtendedAction(xmlDom, sectionNode, action)
5370
5371 @staticmethod
5373 """
5374 Adds a <options> configuration section as the next child of a parent.
5375
5376 We add the following fields to the document::
5377
5378 startingDay //cb_config/options/starting_day
5379 workingDir //cb_config/options/working_dir
5380 backupUser //cb_config/options/backup_user
5381 backupGroup //cb_config/options/backup_group
5382 rcpCommand //cb_config/options/rcp_command
5383 rshCommand //cb_config/options/rsh_command
5384 cbackCommand //cb_config/options/cback_command
5385 managedActions //cb_config/options/managed_actions
5386
5387 We also add groups of the following items, one list element per
5388 item::
5389
5390 overrides //cb_config/options/override
5391 hooks //cb_config/options/pre_action_hook
5392 hooks //cb_config/options/post_action_hook
5393
5394 The individual override items are added by L{_addOverride}. The
5395 individual hook items are added by L{_addHook}.
5396
5397 If C{optionsConfig} is C{None}, then no container will be added.
5398
5399 @param xmlDom: DOM tree as from L{createOutputDom}.
5400 @param parentNode: Parent that the section should be appended to.
5401 @param optionsConfig: Options configuration section to be added to the document.
5402 """
5403 if optionsConfig is not None:
5404 sectionNode = addContainerNode(xmlDom, parentNode, "options")
5405 addStringNode(xmlDom, sectionNode, "starting_day", optionsConfig.startingDay)
5406 addStringNode(xmlDom, sectionNode, "working_dir", optionsConfig.workingDir)
5407 addStringNode(xmlDom, sectionNode, "backup_user", optionsConfig.backupUser)
5408 addStringNode(xmlDom, sectionNode, "backup_group", optionsConfig.backupGroup)
5409 addStringNode(xmlDom, sectionNode, "rcp_command", optionsConfig.rcpCommand)
5410 addStringNode(xmlDom, sectionNode, "rsh_command", optionsConfig.rshCommand)
5411 addStringNode(xmlDom, sectionNode, "cback_command", optionsConfig.cbackCommand)
5412 managedActions = Config._buildCommaSeparatedString(optionsConfig.managedActions)
5413 addStringNode(xmlDom, sectionNode, "managed_actions", managedActions)
5414 if optionsConfig.overrides is not None:
5415 for override in optionsConfig.overrides:
5416 Config._addOverride(xmlDom, sectionNode, override)
5417 if optionsConfig.hooks is not None:
5418 for hook in optionsConfig.hooks:
5419 Config._addHook(xmlDom, sectionNode, hook)
5420
5421 @staticmethod
5422 - def _addPeers(xmlDom, parentNode, peersConfig):
5423 """
5424 Adds a <peers> configuration section as the next child of a parent.
5425
5426 We add groups of the following items, one list element per
5427 item::
5428
5429 localPeers //cb_config/peers/peer
5430 remotePeers //cb_config/peers/peer
5431
5432 The individual local and remote peer entries are added by
5433 L{_addLocalPeer} and L{_addRemotePeer}, respectively.
5434
5435 If C{peersConfig} is C{None}, then no container will be added.
5436
5437 @param xmlDom: DOM tree as from L{createOutputDom}.
5438 @param parentNode: Parent that the section should be appended to.
5439 @param peersConfig: Peers configuration section to be added to the document.
5440 """
5441 if peersConfig is not None:
5442 sectionNode = addContainerNode(xmlDom, parentNode, "peers")
5443 if peersConfig.localPeers is not None:
5444 for localPeer in peersConfig.localPeers:
5445 Config._addLocalPeer(xmlDom, sectionNode, localPeer)
5446 if peersConfig.remotePeers is not None:
5447 for remotePeer in peersConfig.remotePeers:
5448 Config._addRemotePeer(xmlDom, sectionNode, remotePeer)
5449
5450 @staticmethod
5452 """
5453 Adds a <collect> configuration section as the next child of a parent.
5454
5455 We add the following fields to the document::
5456
5457 targetDir //cb_config/collect/collect_dir
5458 collectMode //cb_config/collect/collect_mode
5459 archiveMode //cb_config/collect/archive_mode
5460 ignoreFile //cb_config/collect/ignore_file
5461
5462 We also add groups of the following items, one list element per
5463 item::
5464
5465 absoluteExcludePaths //cb_config/collect/exclude/abs_path
5466 excludePatterns //cb_config/collect/exclude/pattern
5467 collectFiles //cb_config/collect/file
5468 collectDirs //cb_config/collect/dir
5469
5470 The individual collect files are added by L{_addCollectFile} and
5471 individual collect directories are added by L{_addCollectDir}.
5472
5473 If C{collectConfig} is C{None}, then no container will be added.
5474
5475 @param xmlDom: DOM tree as from L{createOutputDom}.
5476 @param parentNode: Parent that the section should be appended to.
5477 @param collectConfig: Collect configuration section to be added to the document.
5478 """
5479 if collectConfig is not None:
5480 sectionNode = addContainerNode(xmlDom, parentNode, "collect")
5481 addStringNode(xmlDom, sectionNode, "collect_dir", collectConfig.targetDir)
5482 addStringNode(xmlDom, sectionNode, "collect_mode", collectConfig.collectMode)
5483 addStringNode(xmlDom, sectionNode, "archive_mode", collectConfig.archiveMode)
5484 addStringNode(xmlDom, sectionNode, "ignore_file", collectConfig.ignoreFile)
5485 if ((collectConfig.absoluteExcludePaths is not None and collectConfig.absoluteExcludePaths != []) or
5486 (collectConfig.excludePatterns is not None and collectConfig.excludePatterns != [])):
5487 excludeNode = addContainerNode(xmlDom, sectionNode, "exclude")
5488 if collectConfig.absoluteExcludePaths is not None:
5489 for absolutePath in collectConfig.absoluteExcludePaths:
5490 addStringNode(xmlDom, excludeNode, "abs_path", absolutePath)
5491 if collectConfig.excludePatterns is not None:
5492 for pattern in collectConfig.excludePatterns:
5493 addStringNode(xmlDom, excludeNode, "pattern", pattern)
5494 if collectConfig.collectFiles is not None:
5495 for collectFile in collectConfig.collectFiles:
5496 Config._addCollectFile(xmlDom, sectionNode, collectFile)
5497 if collectConfig.collectDirs is not None:
5498 for collectDir in collectConfig.collectDirs:
5499 Config._addCollectDir(xmlDom, sectionNode, collectDir)
5500
5501 @staticmethod
5502 - def _addStage(xmlDom, parentNode, stageConfig):
5503 """
5504 Adds a <stage> configuration section as the next child of a parent.
5505
5506 We add the following fields to the document::
5507
5508 targetDir //cb_config/stage/staging_dir
5509
5510 We also add groups of the following items, one list element per
5511 item::
5512
5513 localPeers //cb_config/stage/peer
5514 remotePeers //cb_config/stage/peer
5515
5516 The individual local and remote peer entries are added by
5517 L{_addLocalPeer} and L{_addRemotePeer}, respectively.
5518
5519 If C{stageConfig} is C{None}, then no container will be added.
5520
5521 @param xmlDom: DOM tree as from L{createOutputDom}.
5522 @param parentNode: Parent that the section should be appended to.
5523 @param stageConfig: Stage configuration section to be added to the document.
5524 """
5525 if stageConfig is not None:
5526 sectionNode = addContainerNode(xmlDom, parentNode, "stage")
5527 addStringNode(xmlDom, sectionNode, "staging_dir", stageConfig.targetDir)
5528 if stageConfig.localPeers is not None:
5529 for localPeer in stageConfig.localPeers:
5530 Config._addLocalPeer(xmlDom, sectionNode, localPeer)
5531 if stageConfig.remotePeers is not None:
5532 for remotePeer in stageConfig.remotePeers:
5533 Config._addRemotePeer(xmlDom, sectionNode, remotePeer)
5534
5535 @staticmethod
5536 - def _addStore(xmlDom, parentNode, storeConfig):
5537 """
5538 Adds a <store> configuration section as the next child of a parent.
5539
5540 We add the following fields to the document::
5541
5542 sourceDir //cb_config/store/source_dir
5543 mediaType //cb_config/store/media_type
5544 deviceType //cb_config/store/device_type
5545 devicePath //cb_config/store/target_device
5546 deviceScsiId //cb_config/store/target_scsi_id
5547 driveSpeed //cb_config/store/drive_speed
5548 checkData //cb_config/store/check_data
5549 checkMedia //cb_config/store/check_media
5550 warnMidnite //cb_config/store/warn_midnite
5551 noEject //cb_config/store/no_eject
5552 refreshMediaDelay //cb_config/store/refresh_media_delay
5553 ejectDelay //cb_config/store/eject_delay
5554
5555 Blanking behavior configuration is added by the L{_addBlankBehavior}
5556 method.
5557
5558 If C{storeConfig} is C{None}, then no container will be added.
5559
5560 @param xmlDom: DOM tree as from L{createOutputDom}.
5561 @param parentNode: Parent that the section should be appended to.
5562 @param storeConfig: Store configuration section to be added to the document.
5563 """
5564 if storeConfig is not None:
5565 sectionNode = addContainerNode(xmlDom, parentNode, "store")
5566 addStringNode(xmlDom, sectionNode, "source_dir", storeConfig.sourceDir)
5567 addStringNode(xmlDom, sectionNode, "media_type", storeConfig.mediaType)
5568 addStringNode(xmlDom, sectionNode, "device_type", storeConfig.deviceType)
5569 addStringNode(xmlDom, sectionNode, "target_device", storeConfig.devicePath)
5570 addStringNode(xmlDom, sectionNode, "target_scsi_id", storeConfig.deviceScsiId)
5571 addIntegerNode(xmlDom, sectionNode, "drive_speed", storeConfig.driveSpeed)
5572 addBooleanNode(xmlDom, sectionNode, "check_data", storeConfig.checkData)
5573 addBooleanNode(xmlDom, sectionNode, "check_media", storeConfig.checkMedia)
5574 addBooleanNode(xmlDom, sectionNode, "warn_midnite", storeConfig.warnMidnite)
5575 addBooleanNode(xmlDom, sectionNode, "no_eject", storeConfig.noEject)
5576 addIntegerNode(xmlDom, sectionNode, "refresh_media_delay", storeConfig.refreshMediaDelay)
5577 addIntegerNode(xmlDom, sectionNode, "eject_delay", storeConfig.ejectDelay)
5578 Config._addBlankBehavior(xmlDom, sectionNode, storeConfig.blankBehavior)
5579
5580 @staticmethod
5581 - def _addPurge(xmlDom, parentNode, purgeConfig):
5582 """
5583 Adds a <purge> configuration section as the next child of a parent.
5584
5585 We add the following fields to the document::
5586
5587 purgeDirs //cb_config/purge/dir
5588
5589 The individual directory entries are added by L{_addPurgeDir}.
5590
5591 If C{purgeConfig} is C{None}, then no container will be added.
5592
5593 @param xmlDom: DOM tree as from L{createOutputDom}.
5594 @param parentNode: Parent that the section should be appended to.
5595 @param purgeConfig: Purge configuration section to be added to the document.
5596 """
5597 if purgeConfig is not None:
5598 sectionNode = addContainerNode(xmlDom, parentNode, "purge")
5599 if purgeConfig.purgeDirs is not None:
5600 for purgeDir in purgeConfig.purgeDirs:
5601 Config._addPurgeDir(xmlDom, sectionNode, purgeDir)
5602
5603 @staticmethod
5605 """
5606 Adds an extended action container as the next child of a parent.
5607
5608 We add the following fields to the document::
5609
5610 name action/name
5611 module action/module
5612 function action/function
5613 index action/index
5614 dependencies action/depends
5615
5616 Dependencies are added by the L{_addDependencies} method.
5617
5618 The <action> node itself is created as the next child of the parent node.
5619 This method only adds one action node. The parent must loop for each action
5620 in the C{ExtensionsConfig} object.
5621
5622 If C{action} is C{None}, this method call will be a no-op.
5623
5624 @param xmlDom: DOM tree as from L{createOutputDom}.
5625 @param parentNode: Parent that the section should be appended to.
5626 @param action: Purge directory to be added to the document.
5627 """
5628 if action is not None:
5629 sectionNode = addContainerNode(xmlDom, parentNode, "action")
5630 addStringNode(xmlDom, sectionNode, "name", action.name)
5631 addStringNode(xmlDom, sectionNode, "module", action.module)
5632 addStringNode(xmlDom, sectionNode, "function", action.function)
5633 addIntegerNode(xmlDom, sectionNode, "index", action.index)
5634 Config._addDependencies(xmlDom, sectionNode, action.dependencies)
5635
5636 @staticmethod
5638 """
5639 Adds a command override container as the next child of a parent.
5640
5641 We add the following fields to the document::
5642
5643 command override/command
5644 absolutePath override/abs_path
5645
5646 The <override> node itself is created as the next child of the parent
5647 node. This method only adds one override node. The parent must loop for
5648 each override in the C{OptionsConfig} object.
5649
5650 If C{override} is C{None}, this method call will be a no-op.
5651
5652 @param xmlDom: DOM tree as from L{createOutputDom}.
5653 @param parentNode: Parent that the section should be appended to.
5654 @param override: Command override to be added to the document.
5655 """
5656 if override is not None:
5657 sectionNode = addContainerNode(xmlDom, parentNode, "override")
5658 addStringNode(xmlDom, sectionNode, "command", override.command)
5659 addStringNode(xmlDom, sectionNode, "abs_path", override.absolutePath)
5660
5661 @staticmethod
5662 - def _addHook(xmlDom, parentNode, hook):
5663 """
5664 Adds an action hook container as the next child of a parent.
5665
5666 The behavior varies depending on the value of the C{before} and C{after}
5667 flags on the hook. If the C{before} flag is set, it's a pre-action hook,
5668 and we'll add the following fields::
5669
5670 action pre_action_hook/action
5671 command pre_action_hook/command
5672
5673 If the C{after} flag is set, it's a post-action hook, and we'll add the
5674 following fields::
5675
5676 action post_action_hook/action
5677 command post_action_hook/command
5678
5679 The <pre_action_hook> or <post_action_hook> node itself is created as the
5680 next child of the parent node. This method only adds one hook node. The
5681 parent must loop for each hook in the C{OptionsConfig} object.
5682
5683 If C{hook} is C{None}, this method call will be a no-op.
5684
5685 @param xmlDom: DOM tree as from L{createOutputDom}.
5686 @param parentNode: Parent that the section should be appended to.
5687 @param hook: Command hook to be added to the document.
5688 """
5689 if hook is not None:
5690 if hook.before:
5691 sectionNode = addContainerNode(xmlDom, parentNode, "pre_action_hook")
5692 else:
5693 sectionNode = addContainerNode(xmlDom, parentNode, "post_action_hook")
5694 addStringNode(xmlDom, sectionNode, "action", hook.action)
5695 addStringNode(xmlDom, sectionNode, "command", hook.command)
5696
5697 @staticmethod
5699 """
5700 Adds a collect file container as the next child of a parent.
5701
5702 We add the following fields to the document::
5703
5704 absolutePath dir/abs_path
5705 collectMode dir/collect_mode
5706 archiveMode dir/archive_mode
5707
5708 Note that for consistency with collect directory handling we'll only emit
5709 the preferred C{collect_mode} tag.
5710
5711 The <file> node itself is created as the next child of the parent node.
5712 This method only adds one collect file node. The parent must loop
5713 for each collect file in the C{CollectConfig} object.
5714
5715 If C{collectFile} is C{None}, this method call will be a no-op.
5716
5717 @param xmlDom: DOM tree as from L{createOutputDom}.
5718 @param parentNode: Parent that the section should be appended to.
5719 @param collectFile: Collect file to be added to the document.
5720 """
5721 if collectFile is not None:
5722 sectionNode = addContainerNode(xmlDom, parentNode, "file")
5723 addStringNode(xmlDom, sectionNode, "abs_path", collectFile.absolutePath)
5724 addStringNode(xmlDom, sectionNode, "collect_mode", collectFile.collectMode)
5725 addStringNode(xmlDom, sectionNode, "archive_mode", collectFile.archiveMode)
5726
5727 @staticmethod
5729 """
5730 Adds a collect directory container as the next child of a parent.
5731
5732 We add the following fields to the document::
5733
5734 absolutePath dir/abs_path
5735 collectMode dir/collect_mode
5736 archiveMode dir/archive_mode
5737 ignoreFile dir/ignore_file
5738 linkDepth dir/link_depth
5739 dereference dir/dereference
5740 recursionLevel dir/recursion_level
5741
5742 Note that an original XML document might have listed the collect mode
5743 using the C{mode} tag, since we accept both C{collect_mode} and C{mode}.
5744 However, here we'll only emit the preferred C{collect_mode} tag.
5745
5746 We also add groups of the following items, one list element per item::
5747
5748 absoluteExcludePaths dir/exclude/abs_path
5749 relativeExcludePaths dir/exclude/rel_path
5750 excludePatterns dir/exclude/pattern
5751
5752 The <dir> node itself is created as the next child of the parent node.
5753 This method only adds one collect directory node. The parent must loop
5754 for each collect directory in the C{CollectConfig} object.
5755
5756 If C{collectDir} is C{None}, this method call will be a no-op.
5757
5758 @param xmlDom: DOM tree as from L{createOutputDom}.
5759 @param parentNode: Parent that the section should be appended to.
5760 @param collectDir: Collect directory to be added to the document.
5761 """
5762 if collectDir is not None:
5763 sectionNode = addContainerNode(xmlDom, parentNode, "dir")
5764 addStringNode(xmlDom, sectionNode, "abs_path", collectDir.absolutePath)
5765 addStringNode(xmlDom, sectionNode, "collect_mode", collectDir.collectMode)
5766 addStringNode(xmlDom, sectionNode, "archive_mode", collectDir.archiveMode)
5767 addStringNode(xmlDom, sectionNode, "ignore_file", collectDir.ignoreFile)
5768 addIntegerNode(xmlDom, sectionNode, "link_depth", collectDir.linkDepth)
5769 addBooleanNode(xmlDom, sectionNode, "dereference", collectDir.dereference)
5770 addIntegerNode(xmlDom, sectionNode, "recursion_level", collectDir.recursionLevel)
5771 if ((collectDir.absoluteExcludePaths is not None and collectDir.absoluteExcludePaths != []) or
5772 (collectDir.relativeExcludePaths is not None and collectDir.relativeExcludePaths != []) or
5773 (collectDir.excludePatterns is not None and collectDir.excludePatterns != [])):
5774 excludeNode = addContainerNode(xmlDom, sectionNode, "exclude")
5775 if collectDir.absoluteExcludePaths is not None:
5776 for absolutePath in collectDir.absoluteExcludePaths:
5777 addStringNode(xmlDom, excludeNode, "abs_path", absolutePath)
5778 if collectDir.relativeExcludePaths is not None:
5779 for relativePath in collectDir.relativeExcludePaths:
5780 addStringNode(xmlDom, excludeNode, "rel_path", relativePath)
5781 if collectDir.excludePatterns is not None:
5782 for pattern in collectDir.excludePatterns:
5783 addStringNode(xmlDom, excludeNode, "pattern", pattern)
5784
5785 @staticmethod
5787 """
5788 Adds a local peer container as the next child of a parent.
5789
5790 We add the following fields to the document::
5791
5792 name peer/name
5793 collectDir peer/collect_dir
5794 ignoreFailureMode peer/ignore_failures
5795
5796 Additionally, C{peer/type} is filled in with C{"local"}, since this is a
5797 local peer.
5798
5799 The <peer> node itself is created as the next child of the parent node.
5800 This method only adds one peer node. The parent must loop for each peer
5801 in the C{StageConfig} object.
5802
5803 If C{localPeer} is C{None}, this method call will be a no-op.
5804
5805 @param xmlDom: DOM tree as from L{createOutputDom}.
5806 @param parentNode: Parent that the section should be appended to.
5807 @param localPeer: Purge directory to be added to the document.
5808 """
5809 if localPeer is not None:
5810 sectionNode = addContainerNode(xmlDom, parentNode, "peer")
5811 addStringNode(xmlDom, sectionNode, "name", localPeer.name)
5812 addStringNode(xmlDom, sectionNode, "type", "local")
5813 addStringNode(xmlDom, sectionNode, "collect_dir", localPeer.collectDir)
5814 addStringNode(xmlDom, sectionNode, "ignore_failures", localPeer.ignoreFailureMode)
5815
5816 @staticmethod
5818 """
5819 Adds a remote peer container as the next child of a parent.
5820
5821 We add the following fields to the document::
5822
5823 name peer/name
5824 collectDir peer/collect_dir
5825 remoteUser peer/backup_user
5826 rcpCommand peer/rcp_command
5827 rcpCommand peer/rcp_command
5828 rshCommand peer/rsh_command
5829 cbackCommand peer/cback_command
5830 ignoreFailureMode peer/ignore_failures
5831 managed peer/managed
5832 managedActions peer/managed_actions
5833
5834 Additionally, C{peer/type} is filled in with C{"remote"}, since this is a
5835 remote peer.
5836
5837 The <peer> node itself is created as the next child of the parent node.
5838 This method only adds one peer node. The parent must loop for each peer
5839 in the C{StageConfig} object.
5840
5841 If C{remotePeer} is C{None}, this method call will be a no-op.
5842
5843 @param xmlDom: DOM tree as from L{createOutputDom}.
5844 @param parentNode: Parent that the section should be appended to.
5845 @param remotePeer: Purge directory to be added to the document.
5846 """
5847 if remotePeer is not None:
5848 sectionNode = addContainerNode(xmlDom, parentNode, "peer")
5849 addStringNode(xmlDom, sectionNode, "name", remotePeer.name)
5850 addStringNode(xmlDom, sectionNode, "type", "remote")
5851 addStringNode(xmlDom, sectionNode, "collect_dir", remotePeer.collectDir)
5852 addStringNode(xmlDom, sectionNode, "backup_user", remotePeer.remoteUser)
5853 addStringNode(xmlDom, sectionNode, "rcp_command", remotePeer.rcpCommand)
5854 addStringNode(xmlDom, sectionNode, "rsh_command", remotePeer.rshCommand)
5855 addStringNode(xmlDom, sectionNode, "cback_command", remotePeer.cbackCommand)
5856 addStringNode(xmlDom, sectionNode, "ignore_failures", remotePeer.ignoreFailureMode)
5857 addBooleanNode(xmlDom, sectionNode, "managed", remotePeer.managed)
5858 managedActions = Config._buildCommaSeparatedString(remotePeer.managedActions)
5859 addStringNode(xmlDom, sectionNode, "managed_actions", managedActions)
5860
5861 @staticmethod
5863 """
5864 Adds a purge directory container as the next child of a parent.
5865
5866 We add the following fields to the document::
5867
5868 absolutePath dir/abs_path
5869 retainDays dir/retain_days
5870
5871 The <dir> node itself is created as the next child of the parent node.
5872 This method only adds one purge directory node. The parent must loop for
5873 each purge directory in the C{PurgeConfig} object.
5874
5875 If C{purgeDir} is C{None}, this method call will be a no-op.
5876
5877 @param xmlDom: DOM tree as from L{createOutputDom}.
5878 @param parentNode: Parent that the section should be appended to.
5879 @param purgeDir: Purge directory to be added to the document.
5880 """
5881 if purgeDir is not None:
5882 sectionNode = addContainerNode(xmlDom, parentNode, "dir")
5883 addStringNode(xmlDom, sectionNode, "abs_path", purgeDir.absolutePath)
5884 addIntegerNode(xmlDom, sectionNode, "retain_days", purgeDir.retainDays)
5885
5886 @staticmethod
5888 """
5889 Adds a extended action dependencies to parent node.
5890
5891 We add the following fields to the document::
5892
5893 runBefore depends/run_before
5894 runAfter depends/run_after
5895
5896 If C{dependencies} is C{None}, this method call will be a no-op.
5897
5898 @param xmlDom: DOM tree as from L{createOutputDom}.
5899 @param parentNode: Parent that the section should be appended to.
5900 @param dependencies: C{ActionDependencies} object to be added to the document
5901 """
5902 if dependencies is not None:
5903 sectionNode = addContainerNode(xmlDom, parentNode, "depends")
5904 runBefore = Config._buildCommaSeparatedString(dependencies.beforeList)
5905 runAfter = Config._buildCommaSeparatedString(dependencies.afterList)
5906 addStringNode(xmlDom, sectionNode, "run_before", runBefore)
5907 addStringNode(xmlDom, sectionNode, "run_after", runAfter)
5908
5909 @staticmethod
5911 """
5912 Creates a comma-separated string from a list of values.
5913
5914 As a special case, if C{valueList} is C{None}, then C{None} will be
5915 returned.
5916
5917 @param valueList: List of values to be placed into a string
5918
5919 @return: Values from valueList as a comma-separated string.
5920 """
5921 if valueList is None:
5922 return None
5923 return ",".join(valueList)
5924
5925 @staticmethod
5927 """
5928 Adds a blanking behavior container as the next child of a parent.
5929
5930 We add the following fields to the document::
5931
5932 blankMode blank_behavior/mode
5933 blankFactor blank_behavior/factor
5934
5935 The <blank_behavior> node itself is created as the next child of the
5936 parent node.
5937
5938 If C{blankBehavior} is C{None}, this method call will be a no-op.
5939
5940 @param xmlDom: DOM tree as from L{createOutputDom}.
5941 @param parentNode: Parent that the section should be appended to.
5942 @param blankBehavior: Blanking behavior to be added to the document.
5943 """
5944 if blankBehavior is not None:
5945 sectionNode = addContainerNode(xmlDom, parentNode, "blank_behavior")
5946 addStringNode(xmlDom, sectionNode, "mode", blankBehavior.blankMode)
5947 addStringNode(xmlDom, sectionNode, "factor", blankBehavior.blankFactor)
5948
5949
5950
5951
5952
5953
5955 """
5956 Validates configuration contents per rules discussed in module
5957 documentation.
5958
5959 This is the second pass at validation. It ensures that any filled-in
5960 section contains valid data. Any sections which is not set to C{None} is
5961 validated per the rules for that section, laid out in the module
5962 documentation (above).
5963
5964 @raise ValueError: If configuration is invalid.
5965 """
5966 self._validateReference()
5967 self._validateExtensions()
5968 self._validateOptions()
5969 self._validatePeers()
5970 self._validateCollect()
5971 self._validateStage()
5972 self._validateStore()
5973 self._validatePurge()
5974
5976 """
5977 Validates reference configuration.
5978 There are currently no reference-related validations.
5979 @raise ValueError: If reference configuration is invalid.
5980 """
5981 pass
5982
5984 """
5985 Validates extensions configuration.
5986
5987 The list of actions may be either C{None} or an empty list C{[]} if
5988 desired. Each extended action must include a name, a module, and a
5989 function.
5990
5991 Then, if the order mode is None or "index", an index is required; and if
5992 the order mode is "dependency", dependency information is required.
5993
5994 @raise ValueError: If reference configuration is invalid.
5995 """
5996 if self.extensions is not None:
5997 if self.extensions.actions is not None:
5998 names = []
5999 for action in self.extensions.actions:
6000 if action.name is None:
6001 raise ValueError("Each extended action must set a name.")
6002 names.append(action.name)
6003 if action.module is None:
6004 raise ValueError("Each extended action must set a module.")
6005 if action.function is None:
6006 raise ValueError("Each extended action must set a function.")
6007 if self.extensions.orderMode is None or self.extensions.orderMode == "index":
6008 if action.index is None:
6009 raise ValueError("Each extended action must set an index, based on order mode.")
6010 elif self.extensions.orderMode == "dependency":
6011 if action.dependencies is None:
6012 raise ValueError("Each extended action must set dependency information, based on order mode.")
6013 checkUnique("Duplicate extension names exist:", names)
6014
6016 """
6017 Validates options configuration.
6018
6019 All fields must be filled in except the rsh command. The rcp and rsh
6020 commands are used as default values for all remote peers. Remote peers
6021 can also rely on the backup user as the default remote user name if they
6022 choose.
6023
6024 @raise ValueError: If reference configuration is invalid.
6025 """
6026 if self.options is not None:
6027 if self.options.startingDay is None:
6028 raise ValueError("Options section starting day must be filled in.")
6029 if self.options.workingDir is None:
6030 raise ValueError("Options section working directory must be filled in.")
6031 if self.options.backupUser is None:
6032 raise ValueError("Options section backup user must be filled in.")
6033 if self.options.backupGroup is None:
6034 raise ValueError("Options section backup group must be filled in.")
6035 if self.options.rcpCommand is None:
6036 raise ValueError("Options section remote copy command must be filled in.")
6037
6045
6047 """
6048 Validates collect configuration.
6049
6050 The target directory must be filled in. The collect mode, archive mode,
6051 ignore file, and recursion level are all optional. The list of absolute
6052 paths to exclude and patterns to exclude may be either C{None} or an
6053 empty list C{[]} if desired.
6054
6055 Each collect directory entry must contain an absolute path to collect,
6056 and then must either be able to take collect mode, archive mode and
6057 ignore file configuration from the parent C{CollectConfig} object, or
6058 must set each value on its own. The list of absolute paths to exclude,
6059 relative paths to exclude and patterns to exclude may be either C{None}
6060 or an empty list C{[]} if desired. Any list of absolute paths to exclude
6061 or patterns to exclude will be combined with the same list in the
6062 C{CollectConfig} object to make the complete list for a given directory.
6063
6064 @raise ValueError: If collect configuration is invalid.
6065 """
6066 if self.collect is not None:
6067 if self.collect.targetDir is None:
6068 raise ValueError("Collect section target directory must be filled in.")
6069 if self.collect.collectFiles is not None:
6070 for collectFile in self.collect.collectFiles:
6071 if collectFile.absolutePath is None:
6072 raise ValueError("Each collect file must set an absolute path.")
6073 if self.collect.collectMode is None and collectFile.collectMode is None:
6074 raise ValueError("Collect mode must either be set in parent collect section or individual collect file.")
6075 if self.collect.archiveMode is None and collectFile.archiveMode is None:
6076 raise ValueError("Archive mode must either be set in parent collect section or individual collect file.")
6077 if self.collect.collectDirs is not None:
6078 for collectDir in self.collect.collectDirs:
6079 if collectDir.absolutePath is None:
6080 raise ValueError("Each collect directory must set an absolute path.")
6081 if self.collect.collectMode is None and collectDir.collectMode is None:
6082 raise ValueError("Collect mode must either be set in parent collect section or individual collect directory.")
6083 if self.collect.archiveMode is None and collectDir.archiveMode is None:
6084 raise ValueError("Archive mode must either be set in parent collect section or individual collect directory.")
6085 if self.collect.ignoreFile is None and collectDir.ignoreFile is None:
6086 raise ValueError("Ignore file must either be set in parent collect section or individual collect directory.")
6087 if (collectDir.linkDepth is None or collectDir.linkDepth < 1) and collectDir.dereference:
6088 raise ValueError("Dereference flag is only valid when a non-zero link depth is in use.")
6089
6091 """
6092 Validates stage configuration.
6093
6094 The target directory must be filled in, and the peers are
6095 also validated.
6096
6097 Peers are only required in this section if the peers configuration
6098 section is not filled in. However, if any peers are filled in
6099 here, they override the peers configuration and must meet the
6100 validation criteria in L{_validatePeerList}.
6101
6102 @raise ValueError: If stage configuration is invalid.
6103 """
6104 if self.stage is not None:
6105 if self.stage.targetDir is None:
6106 raise ValueError("Stage section target directory must be filled in.")
6107 if self.peers is None:
6108
6109 self._validatePeerList(self.stage.localPeers, self.stage.remotePeers)
6110 else:
6111
6112
6113 if self.stage.hasPeers():
6114 self._validatePeerList(self.stage.localPeers, self.stage.remotePeers)
6115
6117 """
6118 Validates store configuration.
6119
6120 The device type, drive speed, and blanking behavior are optional. All
6121 other values are required. Missing booleans will be set to defaults.
6122
6123 If blanking behavior is provided, then both a blanking mode and a
6124 blanking factor are required.
6125
6126 The image writer functionality in the C{writer} module is supposed to be
6127 able to handle a device speed of C{None}.
6128
6129 Any caller which needs a "real" (non-C{None}) value for the device type
6130 can use C{DEFAULT_DEVICE_TYPE}, which is guaranteed to be sensible.
6131
6132 This is also where we make sure that the media type -- which is already a
6133 valid type -- matches up properly with the device type.
6134
6135 @raise ValueError: If store configuration is invalid.
6136 """
6137 if self.store is not None:
6138 if self.store.sourceDir is None:
6139 raise ValueError("Store section source directory must be filled in.")
6140 if self.store.mediaType is None:
6141 raise ValueError("Store section media type must be filled in.")
6142 if self.store.devicePath is None:
6143 raise ValueError("Store section device path must be filled in.")
6144 if self.store.deviceType is None or self.store.deviceType == "cdwriter":
6145 if self.store.mediaType not in VALID_CD_MEDIA_TYPES:
6146 raise ValueError("Media type must match device type.")
6147 elif self.store.deviceType == "dvdwriter":
6148 if self.store.mediaType not in VALID_DVD_MEDIA_TYPES:
6149 raise ValueError("Media type must match device type.")
6150 if self.store.blankBehavior is not None:
6151 if self.store.blankBehavior.blankMode is None and self.store.blankBehavior.blankFactor is None:
6152 raise ValueError("If blanking behavior is provided, all values must be filled in.")
6153
6155 """
6156 Validates purge configuration.
6157
6158 The list of purge directories may be either C{None} or an empty list
6159 C{[]} if desired. All purge directories must contain a path and a retain
6160 days value.
6161
6162 @raise ValueError: If purge configuration is invalid.
6163 """
6164 if self.purge is not None:
6165 if self.purge.purgeDirs is not None:
6166 for purgeDir in self.purge.purgeDirs:
6167 if purgeDir.absolutePath is None:
6168 raise ValueError("Each purge directory must set an absolute path.")
6169 if purgeDir.retainDays is None:
6170 raise ValueError("Each purge directory must set a retain days value.")
6171
6173 """
6174 Validates the set of local and remote peers.
6175
6176 Local peers must be completely filled in, including both name and collect
6177 directory. Remote peers must also fill in the name and collect
6178 directory, but can leave the remote user and rcp command unset. In this
6179 case, the remote user is assumed to match the backup user from the
6180 options section and rcp command is taken directly from the options
6181 section.
6182
6183 @param localPeers: List of local peers
6184 @param remotePeers: List of remote peers
6185
6186 @raise ValueError: If stage configuration is invalid.
6187 """
6188 if localPeers is None and remotePeers is None:
6189 raise ValueError("Peer list must contain at least one backup peer.")
6190 if localPeers is None and remotePeers is not None:
6191 if len(remotePeers) < 1:
6192 raise ValueError("Peer list must contain at least one backup peer.")
6193 elif localPeers is not None and remotePeers is None:
6194 if len(localPeers) < 1:
6195 raise ValueError("Peer list must contain at least one backup peer.")
6196 elif localPeers is not None and remotePeers is not None:
6197 if len(localPeers) + len(remotePeers) < 1:
6198 raise ValueError("Peer list must contain at least one backup peer.")
6199 names = []
6200 if localPeers is not None:
6201 for localPeer in localPeers:
6202 if localPeer.name is None:
6203 raise ValueError("Local peers must set a name.")
6204 names.append(localPeer.name)
6205 if localPeer.collectDir is None:
6206 raise ValueError("Local peers must set a collect directory.")
6207 if remotePeers is not None:
6208 for remotePeer in remotePeers:
6209 if remotePeer.name is None:
6210 raise ValueError("Remote peers must set a name.")
6211 names.append(remotePeer.name)
6212 if remotePeer.collectDir is None:
6213 raise ValueError("Remote peers must set a collect directory.")
6214 if (self.options is None or self.options.backupUser is None) and remotePeer.remoteUser is None:
6215 raise ValueError("Remote user must either be set in options section or individual remote peer.")
6216 if (self.options is None or self.options.rcpCommand is None) and remotePeer.rcpCommand is None:
6217 raise ValueError("Remote copy command must either be set in options section or individual remote peer.")
6218 if remotePeer.managed:
6219 if (self.options is None or self.options.rshCommand is None) and remotePeer.rshCommand is None:
6220 raise ValueError("Remote shell command must either be set in options section or individual remote peer.")
6221 if (self.options is None or self.options.cbackCommand is None) and remotePeer.cbackCommand is None:
6222 raise ValueError("Remote cback command must either be set in options section or individual remote peer.")
6223 if ((self.options is None or self.options.managedActions is None or len(self.options.managedActions) < 1)
6224 and (remotePeer.managedActions is None or len(remotePeer.managedActions) < 1)):
6225 raise ValueError("Managed actions list must be set in options section or individual remote peer.")
6226 checkUnique("Duplicate peer names exist:", names)
6227
6234 """
6235 Read a byte size value from an XML document.
6236
6237 A byte size value is an interpreted string value. If the string value
6238 ends with "MB" or "GB", then the string before that is interpreted as
6239 megabytes or gigabytes. Otherwise, it is intepreted as bytes.
6240
6241 @param parent: Parent node to search beneath.
6242 @param name: Name of node to search for.
6243
6244 @return: ByteQuantity parsed from XML document
6245 """
6246 data = readString(parent, name)
6247 if data is None:
6248 return None
6249 data = data.strip()
6250 if data.endswith("KB"):
6251 quantity = data[0:data.rfind("KB")].strip()
6252 units = UNIT_KBYTES
6253 elif data.endswith("MB"):
6254 quantity = data[0:data.rfind("MB")].strip()
6255 units = UNIT_MBYTES
6256 elif data.endswith("GB"):
6257 quantity = data[0:data.rfind("GB")].strip()
6258 units = UNIT_GBYTES
6259 else:
6260 quantity = data.strip()
6261 units = UNIT_BYTES
6262 return ByteQuantity(quantity, units)
6263
6265 """
6266 Adds a text node as the next child of a parent, to contain a byte size.
6267
6268 If the C{byteQuantity} is None, then the node will be created, but will
6269 be empty (i.e. will contain no text node child).
6270
6271 The size in bytes will be normalized. If it is larger than 1.0 GB, it will
6272 be shown in GB ("1.0 GB"). If it is larger than 1.0 MB ("1.0 MB"), it will
6273 be shown in MB. Otherwise, it will be shown in bytes ("423413").
6274
6275 @param xmlDom: DOM tree as from C{impl.createDocument()}.
6276 @param parentNode: Parent node to create child for.
6277 @param nodeName: Name of the new container node.
6278 @param byteQuantity: ByteQuantity object to put into the XML document
6279
6280 @return: Reference to the newly-created node.
6281 """
6282 if byteQuantity is None:
6283 byteString = None
6284 elif byteQuantity.units == UNIT_KBYTES:
6285 byteString = "%s KB" % byteQuantity.quantity
6286 elif byteQuantity.units == UNIT_MBYTES:
6287 byteString = "%s MB" % byteQuantity.quantity
6288 elif byteQuantity.units == UNIT_GBYTES:
6289 byteString = "%s GB" % byteQuantity.quantity
6290 else:
6291 byteString = byteQuantity.quantity
6292 return addStringNode(xmlDom, parentNode, nodeName, byteString)
6293