resources.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. import os
  2. import re
  3. import rope.base.change
  4. import rope.base.fscommands
  5. from rope.base import exceptions
  6. class Resource(object):
  7. """Represents files and folders in a project"""
  8. def __init__(self, project, path):
  9. self.project = project
  10. self._path = path
  11. def move(self, new_location):
  12. """Move resource to `new_location`"""
  13. self._perform_change(rope.base.change.MoveResource(self, new_location),
  14. 'Moving <%s> to <%s>' % (self.path, new_location))
  15. def remove(self):
  16. """Remove resource from the project"""
  17. self._perform_change(rope.base.change.RemoveResource(self),
  18. 'Removing <%s>' % self.path)
  19. def is_folder(self):
  20. """Return true if the resource is a folder"""
  21. def create(self):
  22. """Create this resource"""
  23. def exists(self):
  24. return os.path.exists(self.real_path)
  25. @property
  26. def parent(self):
  27. parent = '/'.join(self.path.split('/')[0:-1])
  28. return self.project.get_folder(parent)
  29. @property
  30. def path(self):
  31. """Return the path of this resource relative to the project root
  32. The path is the list of parent directories separated by '/' followed
  33. by the resource name.
  34. """
  35. return self._path
  36. @property
  37. def name(self):
  38. """Return the name of this resource"""
  39. return self.path.split('/')[-1]
  40. @property
  41. def real_path(self):
  42. """Return the file system path of this resource"""
  43. return self.project._get_resource_path(self.path)
  44. def __eq__(self, obj):
  45. return self.__class__ == obj.__class__ and self.path == obj.path
  46. def __ne__(self, obj):
  47. return not self.__eq__(obj)
  48. def __hash__(self):
  49. return hash(self.path)
  50. def _perform_change(self, change_, description):
  51. changes = rope.base.change.ChangeSet(description)
  52. changes.add_change(change_)
  53. self.project.do(changes)
  54. class File(Resource):
  55. """Represents a file"""
  56. def __init__(self, project, name):
  57. super(File, self).__init__(project, name)
  58. def read(self):
  59. data = self.read_bytes()
  60. try:
  61. return rope.base.fscommands.file_data_to_unicode(data)
  62. except UnicodeDecodeError, e:
  63. raise exceptions.ModuleDecodeError(self.path, e.reason)
  64. def read_bytes(self):
  65. return open(self.real_path, 'rb').read()
  66. def write(self, contents):
  67. try:
  68. if contents == self.read():
  69. return
  70. except IOError:
  71. pass
  72. self._perform_change(rope.base.change.ChangeContents(self, contents),
  73. 'Writing file <%s>' % self.path)
  74. def is_folder(self):
  75. return False
  76. def create(self):
  77. self.parent.create_file(self.name)
  78. class Folder(Resource):
  79. """Represents a folder"""
  80. def __init__(self, project, name):
  81. super(Folder, self).__init__(project, name)
  82. def is_folder(self):
  83. return True
  84. def get_children(self):
  85. """Return the children of this folder"""
  86. result = []
  87. for name in os.listdir(self.real_path):
  88. try:
  89. child = self.get_child(name)
  90. except exceptions.ResourceNotFoundError:
  91. continue
  92. if not self.project.is_ignored(child):
  93. result.append(self.get_child(name))
  94. return result
  95. def create_file(self, file_name):
  96. self._perform_change(
  97. rope.base.change.CreateFile(self, file_name),
  98. 'Creating file <%s>' % self._get_child_path(file_name))
  99. return self.get_child(file_name)
  100. def create_folder(self, folder_name):
  101. self._perform_change(
  102. rope.base.change.CreateFolder(self, folder_name),
  103. 'Creating folder <%s>' % self._get_child_path(folder_name))
  104. return self.get_child(folder_name)
  105. def _get_child_path(self, name):
  106. if self.path:
  107. return self.path + '/' + name
  108. else:
  109. return name
  110. def get_child(self, name):
  111. return self.project.get_resource(self._get_child_path(name))
  112. def has_child(self, name):
  113. try:
  114. self.get_child(name)
  115. return True
  116. except exceptions.ResourceNotFoundError:
  117. return False
  118. def get_files(self):
  119. return [resource for resource in self.get_children()
  120. if not resource.is_folder()]
  121. def get_folders(self):
  122. return [resource for resource in self.get_children()
  123. if resource.is_folder()]
  124. def contains(self, resource):
  125. if self == resource:
  126. return False
  127. return self.path == '' or resource.path.startswith(self.path + '/')
  128. def create(self):
  129. self.parent.create_folder(self.name)
  130. class _ResourceMatcher(object):
  131. def __init__(self):
  132. self.patterns = []
  133. self._compiled_patterns = []
  134. def set_patterns(self, patterns):
  135. """Specify which resources to match
  136. `patterns` is a `list` of `str`\s that can contain ``*`` and
  137. ``?`` signs for matching resource names.
  138. """
  139. self._compiled_patterns = None
  140. self.patterns = patterns
  141. def _add_pattern(self, pattern):
  142. re_pattern = pattern.replace('.', '\\.').\
  143. replace('*', '[^/]*').replace('?', '[^/]').\
  144. replace('//', '/(.*/)?')
  145. re_pattern = '^(.*/)?' + re_pattern + '(/.*)?$'
  146. self.compiled_patterns.append(re.compile(re_pattern))
  147. def does_match(self, resource):
  148. for pattern in self.compiled_patterns:
  149. if pattern.match(resource.path):
  150. return True
  151. path = os.path.join(resource.project.address,
  152. *resource.path.split('/'))
  153. if os.path.islink(path):
  154. return True
  155. return False
  156. @property
  157. def compiled_patterns(self):
  158. if self._compiled_patterns is None:
  159. self._compiled_patterns = []
  160. for pattern in self.patterns:
  161. self._add_pattern(pattern)
  162. return self._compiled_patterns