import os import re import rope.base.change import rope.base.fscommands from rope.base import exceptions class Resource(object): """Represents files and folders in a project""" def __init__(self, project, path): self.project = project self._path = path def move(self, new_location): """Move resource to `new_location`""" self._perform_change(rope.base.change.MoveResource(self, new_location), 'Moving <%s> to <%s>' % (self.path, new_location)) def remove(self): """Remove resource from the project""" self._perform_change(rope.base.change.RemoveResource(self), 'Removing <%s>' % self.path) def is_folder(self): """Return true if the resource is a folder""" def create(self): """Create this resource""" def exists(self): return os.path.exists(self.real_path) @property def parent(self): parent = '/'.join(self.path.split('/')[0:-1]) return self.project.get_folder(parent) @property def path(self): """Return the path of this resource relative to the project root The path is the list of parent directories separated by '/' followed by the resource name. """ return self._path @property def name(self): """Return the name of this resource""" return self.path.split('/')[-1] @property def real_path(self): """Return the file system path of this resource""" return self.project._get_resource_path(self.path) def __eq__(self, obj): return self.__class__ == obj.__class__ and self.path == obj.path def __ne__(self, obj): return not self.__eq__(obj) def __hash__(self): return hash(self.path) def _perform_change(self, change_, description): changes = rope.base.change.ChangeSet(description) changes.add_change(change_) self.project.do(changes) class File(Resource): """Represents a file""" def __init__(self, project, name): super(File, self).__init__(project, name) def read(self): data = self.read_bytes() try: return rope.base.fscommands.file_data_to_unicode(data) except UnicodeDecodeError, e: raise exceptions.ModuleDecodeError(self.path, e.reason) def read_bytes(self): return open(self.real_path, 'rb').read() def write(self, contents): try: if contents == self.read(): return except IOError: pass self._perform_change(rope.base.change.ChangeContents(self, contents), 'Writing file <%s>' % self.path) def is_folder(self): return False def create(self): self.parent.create_file(self.name) class Folder(Resource): """Represents a folder""" def __init__(self, project, name): super(Folder, self).__init__(project, name) def is_folder(self): return True def get_children(self): """Return the children of this folder""" result = [] for name in os.listdir(self.real_path): try: child = self.get_child(name) except exceptions.ResourceNotFoundError: continue if not self.project.is_ignored(child): result.append(self.get_child(name)) return result def create_file(self, file_name): self._perform_change( rope.base.change.CreateFile(self, file_name), 'Creating file <%s>' % self._get_child_path(file_name)) return self.get_child(file_name) def create_folder(self, folder_name): self._perform_change( rope.base.change.CreateFolder(self, folder_name), 'Creating folder <%s>' % self._get_child_path(folder_name)) return self.get_child(folder_name) def _get_child_path(self, name): if self.path: return self.path + '/' + name else: return name def get_child(self, name): return self.project.get_resource(self._get_child_path(name)) def has_child(self, name): try: self.get_child(name) return True except exceptions.ResourceNotFoundError: return False def get_files(self): return [resource for resource in self.get_children() if not resource.is_folder()] def get_folders(self): return [resource for resource in self.get_children() if resource.is_folder()] def contains(self, resource): if self == resource: return False return self.path == '' or resource.path.startswith(self.path + '/') def create(self): self.parent.create_folder(self.name) class _ResourceMatcher(object): def __init__(self): self.patterns = [] self._compiled_patterns = [] def set_patterns(self, patterns): """Specify which resources to match `patterns` is a `list` of `str`\s that can contain ``*`` and ``?`` signs for matching resource names. """ self._compiled_patterns = None self.patterns = patterns def _add_pattern(self, pattern): re_pattern = pattern.replace('.', '\\.').\ replace('*', '[^/]*').replace('?', '[^/]').\ replace('//', '/(.*/)?') re_pattern = '^(.*/)?' + re_pattern + '(/.*)?$' self.compiled_patterns.append(re.compile(re_pattern)) def does_match(self, resource): for pattern in self.compiled_patterns: if pattern.match(resource.path): return True path = os.path.join(resource.project.address, *resource.path.split('/')) if os.path.islink(path): return True return False @property def compiled_patterns(self): if self._compiled_patterns is None: self._compiled_patterns = [] for pattern in self.patterns: self._add_pattern(pattern) return self._compiled_patterns