OLD | NEW |
(Empty) | |
| 1 """Files and folders in a project are represented as resource objects. |
| 2 |
| 3 Files and folders are access through `Resource` objects. `Resource` has |
| 4 two subclasses: `File` and `Folder`. What we care about is that |
| 5 refactorings and `rope.base.change.Change`s use resources. |
| 6 |
| 7 There are two options to create a `Resource` for a path in a project. |
| 8 Note that in these examples `path` is the path to a file or folder |
| 9 relative to the project's root. A project's root folder is represented |
| 10 by an empty string. |
| 11 |
| 12 1) Use the `rope.base.Project.get_resource()` method. E.g.: |
| 13 |
| 14 myresource = myproject.get_resource(path) |
| 15 |
| 16 |
| 17 2) Use the `rope.base.libutils` module. `libutils` has a function |
| 18 named `path_to_resource()`. It takes a project and a path: |
| 19 |
| 20 from rope.base import libutils |
| 21 |
| 22 myresource = libutils.path_to_resource(myproject, path) |
| 23 |
| 24 Once we have a `Resource`, we can retrieve information from it, like |
| 25 getting the path relative to the project's root (via `path`), reading |
| 26 from and writing to the resource, moving the resource, etc. |
| 27 """ |
| 28 |
| 29 import os |
| 30 import re |
| 31 |
| 32 from rope.base import change |
| 33 from rope.base import exceptions |
| 34 from rope.base import fscommands |
| 35 |
| 36 |
| 37 class Resource(object): |
| 38 """Represents files and folders in a project""" |
| 39 |
| 40 def __init__(self, project, path): |
| 41 self.project = project |
| 42 self._path = path |
| 43 |
| 44 def move(self, new_location): |
| 45 """Move resource to `new_location`""" |
| 46 self._perform_change(change.MoveResource(self, new_location), |
| 47 'Moving <%s> to <%s>' % (self.path, new_location)) |
| 48 |
| 49 def remove(self): |
| 50 """Remove resource from the project""" |
| 51 self._perform_change(change.RemoveResource(self), |
| 52 'Removing <%s>' % self.path) |
| 53 |
| 54 def is_folder(self): |
| 55 """Return true if the resource is a folder""" |
| 56 |
| 57 def create(self): |
| 58 """Create this resource""" |
| 59 |
| 60 def exists(self): |
| 61 return os.path.exists(self.real_path) |
| 62 |
| 63 @property |
| 64 def parent(self): |
| 65 parent = '/'.join(self.path.split('/')[0:-1]) |
| 66 return self.project.get_folder(parent) |
| 67 |
| 68 @property |
| 69 def path(self): |
| 70 """Return the path of this resource relative to the project root |
| 71 |
| 72 The path is the list of parent directories separated by '/' followed |
| 73 by the resource name. |
| 74 """ |
| 75 return self._path |
| 76 |
| 77 @property |
| 78 def name(self): |
| 79 """Return the name of this resource""" |
| 80 return self.path.split('/')[-1] |
| 81 |
| 82 @property |
| 83 def real_path(self): |
| 84 """Return the file system path of this resource""" |
| 85 return self.project._get_resource_path(self.path) |
| 86 |
| 87 def __eq__(self, obj): |
| 88 return self.__class__ == obj.__class__ and self.path == obj.path |
| 89 |
| 90 def __ne__(self, obj): |
| 91 return not self.__eq__(obj) |
| 92 |
| 93 def __hash__(self): |
| 94 return hash(self.path) |
| 95 |
| 96 def _perform_change(self, change_, description): |
| 97 changes = change.ChangeSet(description) |
| 98 changes.add_change(change_) |
| 99 self.project.do(changes) |
| 100 |
| 101 |
| 102 class File(Resource): |
| 103 """Represents a file""" |
| 104 |
| 105 def __init__(self, project, name): |
| 106 super(File, self).__init__(project, name) |
| 107 |
| 108 def read(self): |
| 109 data = self.read_bytes() |
| 110 try: |
| 111 return fscommands.file_data_to_unicode(data) |
| 112 except UnicodeDecodeError as e: |
| 113 raise exceptions.ModuleDecodeError(self.path, e.reason) |
| 114 |
| 115 def read_bytes(self): |
| 116 return open(self.real_path, 'rb').read() |
| 117 |
| 118 def write(self, contents): |
| 119 try: |
| 120 if contents == self.read(): |
| 121 return |
| 122 except IOError: |
| 123 pass |
| 124 self._perform_change(change.ChangeContents(self, contents), |
| 125 'Writing file <%s>' % self.path) |
| 126 |
| 127 def is_folder(self): |
| 128 return False |
| 129 |
| 130 def create(self): |
| 131 self.parent.create_file(self.name) |
| 132 |
| 133 |
| 134 class Folder(Resource): |
| 135 """Represents a folder""" |
| 136 |
| 137 def __init__(self, project, name): |
| 138 super(Folder, self).__init__(project, name) |
| 139 |
| 140 def is_folder(self): |
| 141 return True |
| 142 |
| 143 def get_children(self): |
| 144 """Return the children of this folder""" |
| 145 try: |
| 146 children = os.listdir(self.real_path) |
| 147 except OSError: |
| 148 return [] |
| 149 result = [] |
| 150 for name in children: |
| 151 try: |
| 152 child = self.get_child(name) |
| 153 except exceptions.ResourceNotFoundError: |
| 154 continue |
| 155 if not self.project.is_ignored(child): |
| 156 result.append(self.get_child(name)) |
| 157 return result |
| 158 |
| 159 def create_file(self, file_name): |
| 160 self._perform_change( |
| 161 change.CreateFile(self, file_name), |
| 162 'Creating file <%s>' % self._get_child_path(file_name)) |
| 163 return self.get_child(file_name) |
| 164 |
| 165 def create_folder(self, folder_name): |
| 166 self._perform_change( |
| 167 change.CreateFolder(self, folder_name), |
| 168 'Creating folder <%s>' % self._get_child_path(folder_name)) |
| 169 return self.get_child(folder_name) |
| 170 |
| 171 def _get_child_path(self, name): |
| 172 if self.path: |
| 173 return self.path + '/' + name |
| 174 else: |
| 175 return name |
| 176 |
| 177 def get_child(self, name): |
| 178 return self.project.get_resource(self._get_child_path(name)) |
| 179 |
| 180 def has_child(self, name): |
| 181 try: |
| 182 self.get_child(name) |
| 183 return True |
| 184 except exceptions.ResourceNotFoundError: |
| 185 return False |
| 186 |
| 187 def get_files(self): |
| 188 return [resource for resource in self.get_children() |
| 189 if not resource.is_folder()] |
| 190 |
| 191 def get_folders(self): |
| 192 return [resource for resource in self.get_children() |
| 193 if resource.is_folder()] |
| 194 |
| 195 def contains(self, resource): |
| 196 if self == resource: |
| 197 return False |
| 198 return self.path == '' or resource.path.startswith(self.path + '/') |
| 199 |
| 200 def create(self): |
| 201 self.parent.create_folder(self.name) |
| 202 |
| 203 |
| 204 class _ResourceMatcher(object): |
| 205 |
| 206 def __init__(self): |
| 207 self.patterns = [] |
| 208 self._compiled_patterns = [] |
| 209 |
| 210 def set_patterns(self, patterns): |
| 211 """Specify which resources to match |
| 212 |
| 213 `patterns` is a `list` of `str`\s that can contain ``*`` and |
| 214 ``?`` signs for matching resource names. |
| 215 |
| 216 """ |
| 217 self._compiled_patterns = None |
| 218 self.patterns = patterns |
| 219 |
| 220 def _add_pattern(self, pattern): |
| 221 re_pattern = pattern.replace('.', '\\.').\ |
| 222 replace('*', '[^/]*').replace('?', '[^/]').\ |
| 223 replace('//', '/(.*/)?') |
| 224 re_pattern = '^(.*/)?' + re_pattern + '(/.*)?$' |
| 225 self.compiled_patterns.append(re.compile(re_pattern)) |
| 226 |
| 227 def does_match(self, resource): |
| 228 for pattern in self.compiled_patterns: |
| 229 if pattern.match(resource.path): |
| 230 return True |
| 231 path = os.path.join(resource.project.address, |
| 232 *resource.path.split('/')) |
| 233 if os.path.islink(path): |
| 234 return True |
| 235 return False |
| 236 |
| 237 @property |
| 238 def compiled_patterns(self): |
| 239 if self._compiled_patterns is None: |
| 240 self._compiled_patterns = [] |
| 241 for pattern in self.patterns: |
| 242 self._add_pattern(pattern) |
| 243 return self._compiled_patterns |
OLD | NEW |