298 """ |
298 """ |
299 Tests that this node exists. Raises an error it not, otherwise, returns the node itself |
299 Tests that this node exists. Raises an error it not, otherwise, returns the node itself |
300 """ |
300 """ |
301 |
301 |
302 if not self.exists() : |
302 if not self.exists() : |
303 raise Exception("Filesystem node does not exist: %s" % self) |
303 raise NodeErrno(self, errno.ENOENT) |
304 |
304 |
305 return self |
305 return self |
306 |
306 |
307 def path_to (self, node) : |
307 def path_to (self, node) : |
308 """ |
308 """ |
341 |
341 |
342 def __unicode__ (self) : |
342 def __unicode__ (self) : |
343 return self.unicodepath |
343 return self.unicodepath |
344 |
344 |
345 def __repr__ (self) : |
345 def __repr__ (self) : |
346 """ |
|
347 Returns a str representing this dir |
|
348 """ |
|
349 |
|
350 return "Node(%r, %r)" % (self.parent.path, self.fsname) |
346 return "Node(%r, %r)" % (self.parent.path, self.fsname) |
351 |
347 |
352 def __eq__ (self, other) : |
348 def __eq__ (self, other) : |
353 """ |
349 """ |
354 Compare for equality |
350 A Node is equal if compared to another node that shares the same name, and the parents are also equal. |
355 """ |
351 """ |
356 |
352 |
357 return isinstance(other, Node) and self.name == other.name and self.parent == other.parent |
353 return isinstance(other, Node) and self.name == other.name and self.parent == other.parent |
358 |
354 |
359 def __cmp__ (self, other) : |
355 def __cmp__ (self, other) : |
360 """ |
356 """ |
361 Arbitrary comparisons between Nodes |
357 Compare two Nodes or with None. This does not support comparisons with other kinds of objects. |
362 |
358 |
363 >>> cmp(Node(None, 'foo'), Node(None, 'foo')) |
359 >>> cmp(Node(None, 'foo'), Node(None, 'foo')) |
364 0 |
360 0 |
365 >>> cmp(Node(None, 'aaa'), Node(None, 'bbb')) |
361 >>> cmp(Node(None, 'aaa'), Node(None, 'bbb')) |
366 -1 |
362 -1 |
394 A Path is a sequence of Nodes that form a path through a Node tree rooted at some Root. |
390 A Path is a sequence of Nodes that form a path through a Node tree rooted at some Root. |
395 |
391 |
396 Each node must either be the parent or the child of the following node. |
392 Each node must either be the parent or the child of the following node. |
397 |
393 |
398 The first and last nodes may be Files, but all other objects must be Directories. |
394 The first and last nodes may be Files, but all other objects must be Directories. |
|
395 |
|
396 XXX: better to keep Paths symbolic/relative? |
399 """ |
397 """ |
400 |
398 |
401 def __init__ (self, *nodes) : |
399 def __init__ (self, *nodes) : |
402 """ |
400 """ |
403 Initialize with the given node path. |
401 Initialize with the given node path. |
552 return self |
550 return self |
553 |
551 |
554 def open (self, mode='r', encoding=None, errors=None, bufsize=None) : |
552 def open (self, mode='r', encoding=None, errors=None, bufsize=None) : |
555 """ |
553 """ |
556 Wrapper for open/codecs.open. |
554 Wrapper for open/codecs.open. |
557 |
555 """ |
558 Raises an error if read_only mode is set and mode contains any of 'wa+' |
|
559 """ |
|
560 |
|
561 if self.config.read_only and any((c in mode) for c in 'wa+') : |
|
562 raise Exception("Unable to open file for %s due to read_only mode: %s" % (mode, self)) |
|
563 |
556 |
564 if encoding : |
557 if encoding : |
565 return codecs.open(self.path, mode, encoding, errors, bufsize) |
558 return codecs.open(self.path, mode, encoding, errors, bufsize) |
566 |
559 |
567 else : |
560 else : |
576 |
569 |
577 def copy_from (self, file) : |
570 def copy_from (self, file) : |
578 """ |
571 """ |
579 Replace this file with a copy of the given file with default permissions. |
572 Replace this file with a copy of the given file with default permissions. |
580 |
573 |
581 Raises an error if read_only mode is set. |
|
582 |
|
583 XXX: accept mode |
574 XXX: accept mode |
584 """ |
575 """ |
585 |
576 |
586 if self.config.read_only : |
|
587 raise Exception("Not copying file as read_only mode is set: %s -> %s" % (file, self)) |
|
588 |
|
589 # perform the copy |
577 # perform the copy |
590 shutil.copyfile(file.path, self.path) |
578 shutil.copyfile(file.path, self.path) |
591 |
579 |
592 def newer_than (self, file) : |
580 def newer_than (self, file) : |
593 """ |
581 """ |
618 |
606 |
619 def subdir (self, name, create=False) : |
607 def subdir (self, name, create=False) : |
620 """ |
608 """ |
621 Returns a Directory object representing the name underneath this dir. |
609 Returns a Directory object representing the name underneath this dir. |
622 |
610 |
623 If the create option is given, the directory will be created if it does not exist. Note that this will |
611 If the create option is given, the directory will be created if it does not exist. |
624 raise an error if read_only mode is set |
|
625 """ |
612 """ |
626 |
613 |
627 subdir = Directory(self, name=name) |
614 subdir = Directory(self, name=name) |
628 |
615 |
629 if create and not subdir.is_dir() : |
616 if create and not subdir.is_dir() : |
701 """ |
682 """ |
702 |
683 |
703 # build using parent root_path |
684 # build using parent root_path |
704 return os.path.join('..', self.parent.root_path) |
685 return os.path.join('..', self.parent.root_path) |
705 |
686 |
706 def children (self) : |
|
707 """ |
|
708 Yield a series of Node subclasses representing the items in this dir. |
|
709 |
|
710 This uses self.NODE_TYPES to figure out what kind of sub-node object to build. This should be a list of |
|
711 (test_func, node_type) |
|
712 |
|
713 tuples, of which the first is a function that takes a Node as it's sole argument, and returns a boolean. |
|
714 For the first test_func which returns True, a Node-subclass object is constructed using node_type.from_node. |
|
715 |
|
716 XXX: never used |
|
717 """ |
|
718 |
|
719 for node in self : |
|
720 # figure out what type to use |
|
721 for test_func, node_type in self.NODE_TYPES : |
|
722 if test_func(node) : |
|
723 # matches, build |
|
724 yield node_type.from_node(node) |
|
725 |
|
726 else : |
|
727 # unknown file type! |
|
728 raise Exception("unrecongized type of file: %s" % node); |
|
729 |
|
730 # assign default Directory.NODE_TYPES |
|
731 Directory.NODE_TYPES = [ |
|
732 (Node.is_dir, Directory), |
|
733 (Node.is_file, File), |
|
734 ] |
|
735 |
|
736 |
|
737 class Root (Directory) : |
687 class Root (Directory) : |
738 """ |
688 """ |
739 A special Directory that overrides the Node methods to anchor the recursion/etc at some 'real' filesystem path. |
689 A special Directory that overrides the Node methods to anchor the recursion/etc at some 'real' filesystem path. |
740 """ |
690 """ |
741 |
691 |