| Index: tools/telemetry/third_party/rope/rope/base/project.py
|
| diff --git a/tools/telemetry/third_party/rope/rope/base/project.py b/tools/telemetry/third_party/rope/rope/base/project.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..304398aaa8852b762f838008021c460e082c288e
|
| --- /dev/null
|
| +++ b/tools/telemetry/third_party/rope/rope/base/project.py
|
| @@ -0,0 +1,498 @@
|
| +import os
|
| +import shutil
|
| +import sys
|
| +import warnings
|
| +
|
| +import rope.base.fscommands
|
| +from rope.base import exceptions, taskhandle, prefs, history, pycore, utils
|
| +import rope.base.resourceobserver as resourceobserver
|
| +from rope.base.resources import File, Folder, _ResourceMatcher
|
| +from rope.base.exceptions import ModuleNotFoundError
|
| +
|
| +try:
|
| + import pickle
|
| +except ImportError:
|
| + import cPickle as pickle
|
| +try:
|
| + execfile
|
| +except NameError:
|
| + def execfile(fn, global_vars, local_vars):
|
| + with open(fn) as f:
|
| + code = compile(f.read(), fn, 'exec')
|
| + exec(code, global_vars, local_vars)
|
| +
|
| +
|
| +
|
| +class _Project(object):
|
| +
|
| + def __init__(self, fscommands):
|
| + self.observers = []
|
| + self.fscommands = fscommands
|
| + self.prefs = prefs.Prefs()
|
| + self.data_files = _DataFiles(self)
|
| + self._custom_source_folders = []
|
| +
|
| + def get_resource(self, resource_name):
|
| + """Get a resource in a project.
|
| +
|
| + `resource_name` is the path of a resource in a project. It is
|
| + the path of a resource relative to project root. Project root
|
| + folder address is an empty string. If the resource does not
|
| + exist a `exceptions.ResourceNotFound` exception would be
|
| + raised. Use `get_file()` and `get_folder()` when you need to
|
| + get nonexistent `Resource`\s.
|
| +
|
| + """
|
| + path = self._get_resource_path(resource_name)
|
| + if not os.path.exists(path):
|
| + raise exceptions.ResourceNotFoundError(
|
| + 'Resource <%s> does not exist' % resource_name)
|
| + elif os.path.isfile(path):
|
| + return File(self, resource_name)
|
| + elif os.path.isdir(path):
|
| + return Folder(self, resource_name)
|
| + else:
|
| + raise exceptions.ResourceNotFoundError('Unknown resource '
|
| + + resource_name)
|
| +
|
| + def get_module(self, name, folder=None):
|
| + """Returns a `PyObject` if the module was found."""
|
| + # check if this is a builtin module
|
| + pymod = self.pycore.builtin_module(name)
|
| + if pymod is not None:
|
| + return pymod
|
| + module = self.find_module(name, folder)
|
| + if module is None:
|
| + raise ModuleNotFoundError('Module %s not found' % name)
|
| + return self.pycore.resource_to_pyobject(module)
|
| +
|
| + def get_python_path_folders(self):
|
| + result = []
|
| + for src in self.prefs.get('python_path', []) + sys.path:
|
| + try:
|
| + src_folder = get_no_project().get_resource(src)
|
| + result.append(src_folder)
|
| + except exceptions.ResourceNotFoundError:
|
| + pass
|
| + return result
|
| +
|
| + # INFO: It was decided not to cache source folders, since:
|
| + # - Does not take much time when the root folder contains
|
| + # packages, that is most of the time
|
| + # - We need a separate resource observer; `self.observer`
|
| + # does not get notified about module and folder creations
|
| + def get_source_folders(self):
|
| + """Returns project source folders"""
|
| + if self.root is None:
|
| + return []
|
| + result = list(self._custom_source_folders)
|
| + result.extend(self.pycore._find_source_folders(self.root))
|
| + return result
|
| +
|
| + def validate(self, folder):
|
| + """Validate files and folders contained in this folder
|
| +
|
| + It validates all of the files and folders contained in this
|
| + folder if some observers are interested in them.
|
| +
|
| + """
|
| + for observer in list(self.observers):
|
| + observer.validate(folder)
|
| +
|
| + def add_observer(self, observer):
|
| + """Register a `ResourceObserver`
|
| +
|
| + See `FilteredResourceObserver`.
|
| + """
|
| + self.observers.append(observer)
|
| +
|
| + def remove_observer(self, observer):
|
| + """Remove a registered `ResourceObserver`"""
|
| + if observer in self.observers:
|
| + self.observers.remove(observer)
|
| +
|
| + def do(self, changes, task_handle=taskhandle.NullTaskHandle()):
|
| + """Apply the changes in a `ChangeSet`
|
| +
|
| + Most of the time you call this function for committing the
|
| + changes for a refactoring.
|
| + """
|
| + self.history.do(changes, task_handle=task_handle)
|
| +
|
| + def get_pymodule(self, resource, force_errors=False):
|
| + return self.pycore.resource_to_pyobject(resource, force_errors)
|
| +
|
| + def get_pycore(self):
|
| + return self.pycore
|
| +
|
| + def get_file(self, path):
|
| + """Get the file with `path` (it may not exist)"""
|
| + return File(self, path)
|
| +
|
| + def get_folder(self, path):
|
| + """Get the folder with `path` (it may not exist)"""
|
| + return Folder(self, path)
|
| +
|
| + def get_prefs(self):
|
| + return self.prefs
|
| +
|
| + def get_relative_module(self, name, folder, level):
|
| + module = self.find_relative_module(name, folder, level)
|
| + if module is None:
|
| + raise ModuleNotFoundError('Module %s not found' % name)
|
| + return self.pycore.resource_to_pyobject(module)
|
| +
|
| + def find_module(self, modname, folder=None):
|
| + """Returns a resource corresponding to the given module
|
| +
|
| + returns None if it can not be found
|
| + """
|
| + for src in self.get_source_folders():
|
| + module = _find_module_in_folder(src, modname)
|
| + if module is not None:
|
| + return module
|
| + for src in self.get_python_path_folders():
|
| + module = _find_module_in_folder(src, modname)
|
| + if module is not None:
|
| + return module
|
| + if folder is not None:
|
| + module = _find_module_in_folder(folder, modname)
|
| + if module is not None:
|
| + return module
|
| + return None
|
| +
|
| + def find_relative_module(self, modname, folder, level):
|
| + for i in range(level - 1):
|
| + folder = folder.parent
|
| + if modname == '':
|
| + return folder
|
| + else:
|
| + return _find_module_in_folder(folder, modname)
|
| +
|
| + def is_ignored(self, resource):
|
| + return False
|
| +
|
| + def _get_resource_path(self, name):
|
| + pass
|
| +
|
| + @property
|
| + @utils.saveit
|
| + def history(self):
|
| + return history.History(self)
|
| +
|
| + @property
|
| + @utils.saveit
|
| + def pycore(self):
|
| + return pycore.PyCore(self)
|
| +
|
| + def close(self):
|
| + warnings.warn('Cannot close a NoProject',
|
| + DeprecationWarning, stacklevel=2)
|
| +
|
| + ropefolder = None
|
| +
|
| +
|
| +class Project(_Project):
|
| + """A Project containing files and folders"""
|
| +
|
| + def __init__(self, projectroot, fscommands=None,
|
| + ropefolder='.ropeproject', **prefs):
|
| + """A rope project
|
| +
|
| + :parameters:
|
| + - `projectroot`: The address of the root folder of the project
|
| + - `fscommands`: Implements the file system operations used
|
| + by rope; have a look at `rope.base.fscommands`
|
| + - `ropefolder`: The name of the folder in which rope stores
|
| + project configurations and data. Pass `None` for not using
|
| + such a folder at all.
|
| + - `prefs`: Specify project preferences. These values
|
| + overwrite config file preferences.
|
| +
|
| + """
|
| + if projectroot != '/':
|
| + projectroot = _realpath(projectroot).rstrip('/\\')
|
| + self._address = projectroot
|
| + self._ropefolder_name = ropefolder
|
| + if not os.path.exists(self._address):
|
| + os.mkdir(self._address)
|
| + elif not os.path.isdir(self._address):
|
| + raise exceptions.RopeError('Project root exists and'
|
| + ' is not a directory')
|
| + if fscommands is None:
|
| + fscommands = rope.base.fscommands.create_fscommands(self._address)
|
| + super(Project, self).__init__(fscommands)
|
| + self.ignored = _ResourceMatcher()
|
| + self.file_list = _FileListCacher(self)
|
| + self.prefs.add_callback('ignored_resources', self.ignored.set_patterns)
|
| + if ropefolder is not None:
|
| + self.prefs['ignored_resources'] = [ropefolder]
|
| + self._init_prefs(prefs)
|
| + self._init_source_folders()
|
| +
|
| + @utils.deprecated('Delete once deprecated functions are gone')
|
| + def _init_source_folders(self):
|
| + for path in self.prefs.get('source_folders', []):
|
| + folder = self.get_resource(path)
|
| + self._custom_source_folders.append(folder)
|
| +
|
| + def get_files(self):
|
| + return self.file_list.get_files()
|
| +
|
| + def get_python_files(self):
|
| + """Returns all python files available in the project"""
|
| + return [resource for resource in self.get_files()
|
| + if self.pycore.is_python_file(resource)]
|
| +
|
| + def _get_resource_path(self, name):
|
| + return os.path.join(self._address, *name.split('/'))
|
| +
|
| + def _init_ropefolder(self):
|
| + if self.ropefolder is not None:
|
| + if not self.ropefolder.exists():
|
| + self._create_recursively(self.ropefolder)
|
| + if not self.ropefolder.has_child('config.py'):
|
| + config = self.ropefolder.create_file('config.py')
|
| + config.write(self._default_config())
|
| +
|
| + def _create_recursively(self, folder):
|
| + if folder.parent != self.root and not folder.parent.exists():
|
| + self._create_recursively(folder.parent)
|
| + folder.create()
|
| +
|
| + def _init_prefs(self, prefs):
|
| + run_globals = {}
|
| + if self.ropefolder is not None:
|
| + config = self.get_file(self.ropefolder.path + '/config.py')
|
| + run_globals.update({'__name__': '__main__',
|
| + '__builtins__': __builtins__,
|
| + '__file__': config.real_path})
|
| + if config.exists():
|
| + config = self.ropefolder.get_child('config.py')
|
| + execfile(config.real_path, run_globals)
|
| + else:
|
| + exec(self._default_config(), run_globals)
|
| + if 'set_prefs' in run_globals:
|
| + run_globals['set_prefs'](self.prefs)
|
| + for key, value in prefs.items():
|
| + self.prefs[key] = value
|
| + self._init_other_parts()
|
| + self._init_ropefolder()
|
| + if 'project_opened' in run_globals:
|
| + run_globals['project_opened'](self)
|
| +
|
| + def _default_config(self):
|
| + import rope.base.default_config
|
| + import inspect
|
| + return inspect.getsource(rope.base.default_config)
|
| +
|
| + def _init_other_parts(self):
|
| + # Forcing the creation of `self.pycore` to register observers
|
| + self.pycore
|
| +
|
| + def is_ignored(self, resource):
|
| + return self.ignored.does_match(resource)
|
| +
|
| + def sync(self):
|
| + """Closes project open resources"""
|
| + self.close()
|
| +
|
| + def close(self):
|
| + """Closes project open resources"""
|
| + self.data_files.write()
|
| +
|
| + def set(self, key, value):
|
| + """Set the `key` preference to `value`"""
|
| + self.prefs.set(key, value)
|
| +
|
| + @property
|
| + def ropefolder(self):
|
| + if self._ropefolder_name is not None:
|
| + return self.get_folder(self._ropefolder_name)
|
| +
|
| + def validate(self, folder=None):
|
| + if folder is None:
|
| + folder = self.root
|
| + super(Project, self).validate(folder)
|
| +
|
| + root = property(lambda self: self.get_resource(''))
|
| + address = property(lambda self: self._address)
|
| +
|
| +
|
| +class NoProject(_Project):
|
| + """A null object for holding out of project files.
|
| +
|
| + This class is singleton use `get_no_project` global function
|
| + """
|
| +
|
| + def __init__(self):
|
| + fscommands = rope.base.fscommands.FileSystemCommands()
|
| + super(NoProject, self).__init__(fscommands)
|
| +
|
| + def _get_resource_path(self, name):
|
| + real_name = name.replace('/', os.path.sep)
|
| + return _realpath(real_name)
|
| +
|
| + def get_resource(self, name):
|
| + universal_name = _realpath(name).replace(os.path.sep, '/')
|
| + return super(NoProject, self).get_resource(universal_name)
|
| +
|
| + def get_files(self):
|
| + return []
|
| +
|
| + def get_python_files(self):
|
| + return []
|
| +
|
| + _no_project = None
|
| +
|
| +
|
| +def get_no_project():
|
| + if NoProject._no_project is None:
|
| + NoProject._no_project = NoProject()
|
| + return NoProject._no_project
|
| +
|
| +
|
| +class _FileListCacher(object):
|
| +
|
| + def __init__(self, project):
|
| + self.project = project
|
| + self.files = None
|
| + rawobserver = resourceobserver.ResourceObserver(
|
| + self._changed, self._invalid, self._invalid,
|
| + self._invalid, self._invalid)
|
| + self.project.add_observer(rawobserver)
|
| +
|
| + def get_files(self):
|
| + if self.files is None:
|
| + self.files = set()
|
| + self._add_files(self.project.root)
|
| + return self.files
|
| +
|
| + def _add_files(self, folder):
|
| + for child in folder.get_children():
|
| + if child.is_folder():
|
| + self._add_files(child)
|
| + elif not self.project.is_ignored(child):
|
| + self.files.add(child)
|
| +
|
| + def _changed(self, resource):
|
| + if resource.is_folder():
|
| + self.files = None
|
| +
|
| + def _invalid(self, resource, new_resource=None):
|
| + self.files = None
|
| +
|
| +
|
| +class _DataFiles(object):
|
| +
|
| + def __init__(self, project):
|
| + self.project = project
|
| + self.hooks = []
|
| +
|
| + def read_data(self, name, compress=False, import_=False):
|
| + if self.project.ropefolder is None:
|
| + return None
|
| + compress = compress and self._can_compress()
|
| + opener = self._get_opener(compress)
|
| + file = self._get_file(name, compress)
|
| + if not compress and import_:
|
| + self._import_old_files(name)
|
| + if file.exists():
|
| + input = opener(file.real_path, 'rb')
|
| + try:
|
| + result = []
|
| + try:
|
| + while True:
|
| + result.append(pickle.load(input))
|
| + except EOFError:
|
| + pass
|
| + if len(result) == 1:
|
| + return result[0]
|
| + if len(result) > 1:
|
| + return result
|
| + finally:
|
| + input.close()
|
| +
|
| + def write_data(self, name, data, compress=False):
|
| + if self.project.ropefolder is not None:
|
| + compress = compress and self._can_compress()
|
| + file = self._get_file(name, compress)
|
| + opener = self._get_opener(compress)
|
| + output = opener(file.real_path, 'wb')
|
| + try:
|
| + pickle.dump(data, output, 2)
|
| + finally:
|
| + output.close()
|
| +
|
| + def add_write_hook(self, hook):
|
| + self.hooks.append(hook)
|
| +
|
| + def write(self):
|
| + for hook in self.hooks:
|
| + hook()
|
| +
|
| + def _can_compress(self):
|
| + try:
|
| + import gzip # noqa
|
| + return True
|
| + except ImportError:
|
| + return False
|
| +
|
| + def _import_old_files(self, name):
|
| + old = self._get_file(name + '.pickle', False)
|
| + new = self._get_file(name, False)
|
| + if old.exists() and not new.exists():
|
| + shutil.move(old.real_path, new.real_path)
|
| +
|
| + def _get_opener(self, compress):
|
| + if compress:
|
| + try:
|
| + import gzip
|
| + return gzip.open
|
| + except ImportError:
|
| + pass
|
| + return open
|
| +
|
| + def _get_file(self, name, compress):
|
| + path = self.project.ropefolder.path + '/' + name
|
| + if compress:
|
| + path += '.gz'
|
| + return self.project.get_file(path)
|
| +
|
| +
|
| +def _realpath(path):
|
| + """Return the real path of `path`
|
| +
|
| + Is equivalent to ``realpath(abspath(expanduser(path)))``.
|
| +
|
| + Of the particular notice is the hack dealing with the unfortunate
|
| + sitaution of running native-Windows python (os.name == 'nt') inside
|
| + of Cygwin (abspath starts with '/'), which apparently normal
|
| + os.path.realpath completely messes up.
|
| +
|
| + """
|
| + # there is a bug in cygwin for os.path.abspath() for abs paths
|
| + if sys.platform == 'cygwin':
|
| + if path[1:3] == ':\\':
|
| + return path
|
| + elif path[1:3] == ':/':
|
| + path = "/cygdrive/" + path[0] + path[2:]
|
| + return os.path.abspath(os.path.expanduser(path))
|
| + return os.path.realpath(os.path.abspath(os.path.expanduser(path)))
|
| +
|
| +
|
| +def _find_module_in_folder(folder, modname):
|
| + module = folder
|
| + packages = modname.split('.')
|
| + for pkg in packages[:-1]:
|
| + if module.is_folder() and module.has_child(pkg):
|
| + module = module.get_child(pkg)
|
| + else:
|
| + return None
|
| + if module.is_folder():
|
| + if module.has_child(packages[-1]) and \
|
| + module.get_child(packages[-1]).is_folder():
|
| + return module.get_child(packages[-1])
|
| + elif module.has_child(packages[-1] + '.py') and \
|
| + not module.get_child(packages[-1] + '.py').is_folder():
|
| + return module.get_child(packages[-1] + '.py')
|
|
|