Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
marvel
GitHub Repository: marvel/qnf
Path: blob/master/elisp/emacs-for-python/rope-dist/rope/base/project.py
1415 views
1
import cPickle as pickle
2
import os
3
import shutil
4
import sys
5
import warnings
6
7
import rope.base.fscommands
8
from rope.base import exceptions, taskhandle, prefs, history, pycore, utils
9
from rope.base.resourceobserver import *
10
from rope.base.resources import File, Folder, _ResourceMatcher
11
12
13
class _Project(object):
14
15
def __init__(self, fscommands):
16
self.observers = []
17
self.fscommands = fscommands
18
self.prefs = prefs.Prefs()
19
self.data_files = _DataFiles(self)
20
21
def get_resource(self, resource_name):
22
"""Get a resource in a project.
23
24
`resource_name` is the path of a resource in a project. It is
25
the path of a resource relative to project root. Project root
26
folder address is an empty string. If the resource does not
27
exist a `exceptions.ResourceNotFound` exception would be
28
raised. Use `get_file()` and `get_folder()` when you need to
29
get nonexistent `Resource`\s.
30
31
"""
32
path = self._get_resource_path(resource_name)
33
if not os.path.exists(path):
34
raise exceptions.ResourceNotFoundError(
35
'Resource <%s> does not exist' % resource_name)
36
elif os.path.isfile(path):
37
return File(self, resource_name)
38
elif os.path.isdir(path):
39
return Folder(self, resource_name)
40
else:
41
raise exceptions.ResourceNotFoundError('Unknown resource '
42
+ resource_name)
43
44
def validate(self, folder):
45
"""Validate files and folders contained in this folder
46
47
It validates all of the files and folders contained in this
48
folder if some observers are interested in them.
49
50
"""
51
for observer in list(self.observers):
52
observer.validate(folder)
53
54
def add_observer(self, observer):
55
"""Register a `ResourceObserver`
56
57
See `FilteredResourceObserver`.
58
"""
59
self.observers.append(observer)
60
61
def remove_observer(self, observer):
62
"""Remove a registered `ResourceObserver`"""
63
if observer in self.observers:
64
self.observers.remove(observer)
65
66
def do(self, changes, task_handle=taskhandle.NullTaskHandle()):
67
"""Apply the changes in a `ChangeSet`
68
69
Most of the time you call this function for committing the
70
changes for a refactoring.
71
"""
72
self.history.do(changes, task_handle=task_handle)
73
74
def get_pycore(self):
75
return self.pycore
76
77
def get_file(self, path):
78
"""Get the file with `path` (it may not exist)"""
79
return File(self, path)
80
81
def get_folder(self, path):
82
"""Get the folder with `path` (it may not exist)"""
83
return Folder(self, path)
84
85
def is_ignored(self, resource):
86
return False
87
88
def get_prefs(self):
89
return self.prefs
90
91
def _get_resource_path(self, name):
92
pass
93
94
@property
95
@utils.saveit
96
def history(self):
97
return history.History(self)
98
99
@property
100
@utils.saveit
101
def pycore(self):
102
return pycore.PyCore(self)
103
104
def close(self):
105
warnings.warn('Cannot close a NoProject',
106
DeprecationWarning, stacklevel=2)
107
108
ropefolder = None
109
110
111
class Project(_Project):
112
"""A Project containing files and folders"""
113
114
def __init__(self, projectroot, fscommands=None,
115
ropefolder='.ropeproject', **prefs):
116
"""A rope project
117
118
:parameters:
119
- `projectroot`: The address of the root folder of the project
120
- `fscommands`: Implements the file system operations used
121
by rope; have a look at `rope.base.fscommands`
122
- `ropefolder`: The name of the folder in which rope stores
123
project configurations and data. Pass `None` for not using
124
such a folder at all.
125
- `prefs`: Specify project preferences. These values
126
overwrite config file preferences.
127
128
"""
129
if projectroot != '/':
130
projectroot = _realpath(projectroot).rstrip('/\\')
131
self._address = projectroot
132
self._ropefolder_name = ropefolder
133
if not os.path.exists(self._address):
134
os.mkdir(self._address)
135
elif not os.path.isdir(self._address):
136
raise exceptions.RopeError('Project root exists and'
137
' is not a directory')
138
if fscommands is None:
139
fscommands = rope.base.fscommands.create_fscommands(self._address)
140
super(Project, self).__init__(fscommands)
141
self.ignored = _ResourceMatcher()
142
self.file_list = _FileListCacher(self)
143
self.prefs.add_callback('ignored_resources', self.ignored.set_patterns)
144
if ropefolder is not None:
145
self.prefs['ignored_resources'] = [ropefolder]
146
self._init_prefs(prefs)
147
148
def get_files(self):
149
return self.file_list.get_files()
150
151
def _get_resource_path(self, name):
152
return os.path.join(self._address, *name.split('/'))
153
154
def _init_ropefolder(self):
155
if self.ropefolder is not None:
156
if not self.ropefolder.exists():
157
self._create_recursively(self.ropefolder)
158
if not self.ropefolder.has_child('config.py'):
159
config = self.ropefolder.create_file('config.py')
160
config.write(self._default_config())
161
162
def _create_recursively(self, folder):
163
if folder.parent != self.root and not folder.parent.exists():
164
self._create_recursively(folder.parent)
165
folder.create()
166
167
def _init_prefs(self, prefs):
168
run_globals = {}
169
if self.ropefolder is not None:
170
config = self.get_file(self.ropefolder.path + '/config.py')
171
run_globals.update({'__name__': '__main__',
172
'__builtins__': __builtins__,
173
'__file__': config.real_path})
174
if config.exists():
175
config = self.ropefolder.get_child('config.py')
176
execfile(config.real_path, run_globals)
177
else:
178
exec(self._default_config(), run_globals)
179
if 'set_prefs' in run_globals:
180
run_globals['set_prefs'](self.prefs)
181
for key, value in prefs.items():
182
self.prefs[key] = value
183
self._init_other_parts()
184
self._init_ropefolder()
185
if 'project_opened' in run_globals:
186
run_globals['project_opened'](self)
187
188
def _default_config(self):
189
import rope.base.default_config
190
import inspect
191
return inspect.getsource(rope.base.default_config)
192
193
def _init_other_parts(self):
194
# Forcing the creation of `self.pycore` to register observers
195
self.pycore
196
197
def is_ignored(self, resource):
198
return self.ignored.does_match(resource)
199
200
def sync(self):
201
"""Closes project open resources"""
202
self.close()
203
204
def close(self):
205
"""Closes project open resources"""
206
self.data_files.write()
207
208
def set(self, key, value):
209
"""Set the `key` preference to `value`"""
210
self.prefs.set(key, value)
211
212
@property
213
def ropefolder(self):
214
if self._ropefolder_name is not None:
215
return self.get_folder(self._ropefolder_name)
216
217
def validate(self, folder=None):
218
if folder is None:
219
folder = self.root
220
super(Project, self).validate(folder)
221
222
root = property(lambda self: self.get_resource(''))
223
address = property(lambda self: self._address)
224
225
226
class NoProject(_Project):
227
"""A null object for holding out of project files.
228
229
This class is singleton use `get_no_project` global function
230
"""
231
232
def __init__(self):
233
fscommands = rope.base.fscommands.FileSystemCommands()
234
super(NoProject, self).__init__(fscommands)
235
236
def _get_resource_path(self, name):
237
real_name = name.replace('/', os.path.sep)
238
return _realpath(real_name)
239
240
def get_resource(self, name):
241
universal_name = _realpath(name).replace(os.path.sep, '/')
242
return super(NoProject, self).get_resource(universal_name)
243
244
def get_files(self):
245
return []
246
247
_no_project = None
248
249
250
def get_no_project():
251
if NoProject._no_project is None:
252
NoProject._no_project = NoProject()
253
return NoProject._no_project
254
255
256
class _FileListCacher(object):
257
258
def __init__(self, project):
259
self.project = project
260
self.files = None
261
rawobserver = ResourceObserver(
262
self._changed, self._invalid, self._invalid,
263
self._invalid, self._invalid)
264
self.project.add_observer(rawobserver)
265
266
def get_files(self):
267
if self.files is None:
268
self.files = set()
269
self._add_files(self.project.root)
270
return self.files
271
272
def _add_files(self, folder):
273
for child in folder.get_children():
274
if child.is_folder():
275
self._add_files(child)
276
elif not self.project.is_ignored(child):
277
self.files.add(child)
278
279
def _changed(self, resource):
280
if resource.is_folder():
281
self.files = None
282
283
def _invalid(self, resource, new_resource=None):
284
self.files = None
285
286
287
class _DataFiles(object):
288
289
def __init__(self, project):
290
self.project = project
291
self.hooks = []
292
293
def read_data(self, name, compress=False, import_=False):
294
if self.project.ropefolder is None:
295
return None
296
compress = compress and self._can_compress()
297
opener = self._get_opener(compress)
298
file = self._get_file(name, compress)
299
if not compress and import_:
300
self._import_old_files(name)
301
if file.exists():
302
input = opener(file.real_path, 'rb')
303
try:
304
result = []
305
try:
306
while True:
307
result.append(pickle.load(input))
308
except EOFError:
309
pass
310
if len(result) == 1:
311
return result[0]
312
if len(result) > 1:
313
return result
314
finally:
315
input.close()
316
317
def write_data(self, name, data, compress=False):
318
if self.project.ropefolder is not None:
319
compress = compress and self._can_compress()
320
file = self._get_file(name, compress)
321
opener = self._get_opener(compress)
322
output = opener(file.real_path, 'wb')
323
try:
324
pickle.dump(data, output, 2)
325
finally:
326
output.close()
327
328
def add_write_hook(self, hook):
329
self.hooks.append(hook)
330
331
def write(self):
332
for hook in self.hooks:
333
hook()
334
335
def _can_compress(self):
336
try:
337
import gzip
338
return True
339
except ImportError:
340
return False
341
342
def _import_old_files(self, name):
343
old = self._get_file(name + '.pickle', False)
344
new = self._get_file(name, False)
345
if old.exists() and not new.exists():
346
shutil.move(old.real_path, new.real_path)
347
348
def _get_opener(self, compress):
349
if compress:
350
try:
351
import gzip
352
return gzip.open
353
except ImportError:
354
pass
355
return open
356
357
def _get_file(self, name, compress):
358
path = self.project.ropefolder.path + '/' + name
359
if compress:
360
path += '.gz'
361
return self.project.get_file(path)
362
363
364
def _realpath(path):
365
"""Return the real path of `path`
366
367
Is equivalent to ``realpath(abspath(expanduser(path)))``.
368
369
"""
370
# there is a bug in cygwin for os.path.abspath() for abs paths
371
if sys.platform == 'cygwin':
372
if path[1:3] == ':\\':
373
return path
374
return os.path.abspath(os.path.expanduser(path))
375
return os.path.realpath(os.path.abspath(os.path.expanduser(path)))
376
377