Exemple #1
0
 def add(self, path, overwrite=False, **kwargs):
     """
     Add an item to this file listing at the relative or absolute path
     `path` and return the added item.  If the path is absolute, it must
     descend from `self.base`.
     
     See the documentation for `Container.add` for more details.
     
     """
     path = Path(path)
     if path.is_absolute:
         # This is an absolute path.  Ensure that `path` descends from
         # `self.base`, otherwise it does not belong in this file list.
         path = path.relative_to(self.base)
     return super(FileListing, self).add(path, overwrite, **kwargs)
Exemple #2
0
 def remove(self, path):
     """
     Remove the item at the relative or absolute path `path` from this file
     listing and return the item.  If no such item is found (including an
     absolute path that does not descend from `self.base`), return None.
     
     See the documentation for `Container.remove` for more details.
     
     """
     path = Path(path)
     if path.is_absolute:
         # This is an absolute path.  Ensure that `path` descends from
         # `self.base`, otherwise it does not belong in this file list.
         path = path.relative_to(self.base)
     return super(FileListing, self).remove(path)
Exemple #3
0
 def get_partial(self, base=None, depth=-1):
     if base:
         base = Path(base)
         if not base.is_directory:
             raise RuntimeError("Base path must reference a directory.")
         elif base.is_relative:
             base = self.base.join(base)
         elif not base.descends_from(self.base):
             raise RuntimeError("Path does not descend from base.")
         listing = self.get(base)
     else:
         listing = self
         base = self.base
     
     partial = super(FileListing, listing).get_partial(depth)
     partial.base = base
     return partial
Exemple #4
0
 def __init__(self, client_id, base='/', version=VERSION, generator=None):
     super(FileListing, self).__init__()
     self.client_id = client_id
     self.base = Path(base)
     if version != self.VERSION:
         raise RuntimeError("Unsupported file listing version.")
     self.version = version
     self.generator = generator
Exemple #5
0
class FileListing(Container):
    """High-level representation of a file listing."""
    
    VERSION = 1
    GENERATOR = 'libsheep'
    
    def __init__(self, client_id, base='/', version=VERSION, generator=None):
        super(FileListing, self).__init__()
        self.client_id = client_id
        self.base = Path(base)
        if version != self.VERSION:
            raise RuntimeError("Unsupported file listing version.")
        self.version = version
        self.generator = generator
    
    def __repr__(self):
        return 'FileListing(%r, %r)' % (self.client_id, self.base)
    
    def __eq__(self, other):
        if isinstance(other, FileListing):
            if self.client_id != other.client_id or self.base != other.base:
                return False
        return super(FileListing, self).__eq__(other)
    
    def iter_paths(self, depth=-1):
        return super(FileListing, self).iter_paths(self.base, depth)
    
    def _get_base(self):
        return self._base
    
    def _set_base(self, path):
        if not isinstance(path, Path):
            path = Path(path)
        self._base = path
    
    base = property(_get_base, _set_base)
    
    @classmethod
    def from_file(cls, file_or_name):
        """
        Return a `FileListing` instance initialized with contents from
        `file_or_name`, which is a filename or file-like object.
        
        """
        tree = ElementTree.parse(file_or_name)
        return cls.from_element(tree.getroot())
    
    @classmethod
    def from_string(cls, xml_string):
        """
        Return a `FileListing` instance initialized with contents from
        `xml_string`.
        
        """
        element = ElementTree.fromstring(xml_string)
        return cls.from_element(element)
    
    @classmethod
    def from_element(cls, element):
        if element.tag == 'FileListing':
            client_id = element.attrib['CID']
            base = element.attrib['Base']
            version = int(element.attrib['Version'])
            generator = element.get('Generator')
            # TODO: Optional/arbitrary attributes (from extensions, etc.)
            # Create a `FileListing` instance.
            listing = cls(client_id, base, version, generator)
            
            # Add files and directories to the instance.
            for subelement in element:
                if subelement.tag == 'File':
                    listing_file = File.from_element(subelement)
                    listing.contents[listing_file.name] = listing_file
                elif subelement.tag == 'Directory':
                    listing_dir = Directory.from_element(subelement)
                    listing.contents[listing_dir.name] = listing_dir
            
            return listing
        else:
            raise RuntimeError("File listing does not conform to schema.")
    
    def to_element(self):
        element = ElementTree.Element('FileListing')
        element.set('CID', str(self.client_id))
        element.set('Base', unicode(self.base))
        element.set('Version', str(self.version))
        element.set('Generator', self.GENERATOR)
        for child in self.contents.itervalues():
            element.append(child.to_element())
        return element
    
    def serialize(self):
        """Generate and return the XML serialization of the file listing."""
        string_file = StringIO()
        self.write(string_file)
        return string_file.getvalue()
    
    def write(self, file_or_name, mode='w'):
        """
        Serialize the file listing and write it to `file_or_name`, which
        is a filename or file-like object.  If `file_or_name` is a filename,
        it will be opened with the mode given by `mode`.
        
        """
        if isinstance(file_or_name, basestring):
            output_file = open(file_or_name, mode)
        else:
            output_file = file_or_name
        
        root = self.to_element()
        tree = ElementTree.ElementTree(root)
        tree.write(output_file, 'utf-8')
    
    def get(self, path):
        path = Path(path)
        if path.is_absolute:
            # Make this possible later.
            raise RuntimeError("Path does not descend from base.")
        
        names = list(self.base)
        file_name = names.pop()
        parent = self
        for dir_name in names:
            parent = parent[dir_name]
            if not isinstance(parent, Container):
                raise RuntimeError("File not found.")
        if file_name:
            item = parent[file_name]
        else:
            item = parent
        return item
    
    def add(self, path, overwrite=False, **kwargs):
        """
        Add an item to this file listing at the relative or absolute path
        `path` and return the added item.  If the path is absolute, it must
        descend from `self.base`.
        
        See the documentation for `Container.add` for more details.
        
        """
        path = Path(path)
        if path.is_absolute:
            # This is an absolute path.  Ensure that `path` descends from
            # `self.base`, otherwise it does not belong in this file list.
            path = path.relative_to(self.base)
        return super(FileListing, self).add(path, overwrite, **kwargs)
    
    def remove(self, path):
        """
        Remove the item at the relative or absolute path `path` from this file
        listing and return the item.  If no such item is found (including an
        absolute path that does not descend from `self.base`), return None.
        
        See the documentation for `Container.remove` for more details.
        
        """
        path = Path(path)
        if path.is_absolute:
            # This is an absolute path.  Ensure that `path` descends from
            # `self.base`, otherwise it does not belong in this file list.
            path = path.relative_to(self.base)
        return super(FileListing, self).remove(path)

    def get_partial(self, base=None, depth=-1):
        if base:
            base = Path(base)
            if not base.is_directory:
                raise RuntimeError("Base path must reference a directory.")
            elif base.is_relative:
                base = self.base.join(base)
            elif not base.descends_from(self.base):
                raise RuntimeError("Path does not descend from base.")
            listing = self.get(base)
        else:
            listing = self
            base = self.base
        
        partial = super(FileListing, listing).get_partial(depth)
        partial.base = base
        return partial
Exemple #6
0
 def test_backslashes_escaped(self):
     self.assertEquals(Path.escape('\\\\'), r'\\\\')
Exemple #7
0
 def test_slashes_escaped(self):
     self.assertEquals(Path.escape(r'//'), r'\/\/')
Exemple #8
0
 def test_unknown_escape_sequence_is_literal_char(self):
     self.assertEquals(Path.unescape(r'\x'), 'x')
Exemple #9
0
 def test_backslashes_unescaped(self):
     self.assertEquals(Path.unescape(r'\\\\'), '\\\\')
Exemple #10
0
 def test_other_punctuation_unescaped(self):
     s = '`~!@#$%^&*()-_=+[{]}|;:\'",<.>?'
     self.assertEquals(Path.escape(s), s)