Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(239)

Unified Diff: tools/telemetry/third_party/rope/rope/base/change.py

Issue 1132103009: Example of refactoring using rope library. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tools/telemetry/third_party/rope/rope/base/change.py
diff --git a/tools/telemetry/third_party/rope/rope/base/change.py b/tools/telemetry/third_party/rope/rope/base/change.py
new file mode 100644
index 0000000000000000000000000000000000000000..fe2ebf435adb36e28509d56f82ca5a707f78df1a
--- /dev/null
+++ b/tools/telemetry/third_party/rope/rope/base/change.py
@@ -0,0 +1,450 @@
+import datetime
+import difflib
+import os
+import time
+
+import rope.base.fscommands
+from rope.base import taskhandle, exceptions, utils
+
+
+class Change(object):
+ """The base class for changes
+
+ Rope refactorings return `Change` objects. They can be previewed,
+ committed or undone.
+ """
+
+ def do(self, job_set=None):
+ """Perform the change
+
+ .. note:: Do use this directly. Use `Project.do()` instead.
+ """
+
+ def undo(self, job_set=None):
+ """Perform the change
+
+ .. note:: Do use this directly. Use `History.undo()` instead.
+ """
+
+ def get_description(self):
+ """Return the description of this change
+
+ This can be used for previewing the changes.
+ """
+ return str(self)
+
+ def get_changed_resources(self):
+ """Return the list of resources that will be changed"""
+ return []
+
+ @property
+ @utils.saveit
+ def _operations(self):
+ return _ResourceOperations(self.resource.project)
+
+
+class ChangeSet(Change):
+ """A collection of `Change` objects
+
+ This class holds a collection of changes. This class provides
+ these fields:
+
+ * `changes`: the list of changes
+ * `description`: the goal of these changes
+ """
+
+ def __init__(self, description, timestamp=None):
+ self.changes = []
+ self.description = description
+ self.time = timestamp
+
+ def do(self, job_set=taskhandle.NullJobSet()):
+ try:
+ done = []
+ for change in self.changes:
+ change.do(job_set)
+ done.append(change)
+ self.time = time.time()
+ except Exception:
+ for change in done:
+ change.undo()
+ raise
+
+ def undo(self, job_set=taskhandle.NullJobSet()):
+ try:
+ done = []
+ for change in reversed(self.changes):
+ change.undo(job_set)
+ done.append(change)
+ except Exception:
+ for change in done:
+ change.do()
+ raise
+
+ def add_change(self, change):
+ self.changes.append(change)
+
+ def get_description(self):
+ result = [str(self) + ':\n\n\n']
+ for change in self.changes:
+ result.append(change.get_description())
+ result.append('\n')
+ return ''.join(result)
+
+ def __str__(self):
+ if self.time is not None:
+ date = datetime.datetime.fromtimestamp(self.time)
+ if date.date() == datetime.date.today():
+ string_date = 'today'
+ elif date.date() == (datetime.date.today() -
+ datetime.timedelta(1)):
+ string_date = 'yesterday'
+ elif date.year == datetime.date.today().year:
+ string_date = date.strftime('%b %d')
+ else:
+ string_date = date.strftime('%d %b, %Y')
+ string_time = date.strftime('%H:%M:%S')
+ string_time = '%s %s ' % (string_date, string_time)
+ return self.description + ' - ' + string_time
+ return self.description
+
+ def get_changed_resources(self):
+ result = set()
+ for change in self.changes:
+ result.update(change.get_changed_resources())
+ return result
+
+
+def _handle_job_set(function):
+ """A decorator for handling `taskhandle.JobSet`\s
+
+ A decorator for handling `taskhandle.JobSet`\s for `do` and `undo`
+ methods of `Change`\s.
+ """
+ def call(self, job_set=taskhandle.NullJobSet()):
+ job_set.started_job(str(self))
+ function(self)
+ job_set.finished_job()
+ return call
+
+
+class ChangeContents(Change):
+ """A class to change the contents of a file
+
+ Fields:
+
+ * `resource`: The `rope.base.resources.File` to change
+ * `new_contents`: What to write in the file
+ """
+
+ def __init__(self, resource, new_contents, old_contents=None):
+ self.resource = resource
+ # IDEA: Only saving diffs; possible problems when undo/redoing
+ self.new_contents = new_contents
+ self.old_contents = old_contents
+
+ @_handle_job_set
+ def do(self):
+ if self.old_contents is None:
+ self.old_contents = self.resource.read()
+ self._operations.write_file(self.resource, self.new_contents)
+
+ @_handle_job_set
+ def undo(self):
+ if self.old_contents is None:
+ raise exceptions.HistoryError(
+ 'Undoing a change that is not performed yet!')
+ self._operations.write_file(self.resource, self.old_contents)
+
+ def __str__(self):
+ return 'Change <%s>' % self.resource.path
+
+ def get_description(self):
+ new = self.new_contents
+ old = self.old_contents
+ if old is None:
+ if self.resource.exists():
+ old = self.resource.read()
+ else:
+ old = ''
+ result = difflib.unified_diff(
+ old.splitlines(True), new.splitlines(True),
+ 'a/' + self.resource.path, 'b/' + self.resource.path)
+ return ''.join(list(result))
+
+ def get_changed_resources(self):
+ return [self.resource]
+
+
+class MoveResource(Change):
+ """Move a resource to a new location
+
+ Fields:
+
+ * `resource`: The `rope.base.resources.Resource` to move
+ * `new_resource`: The destination for move; It is the moved
+ resource not the folder containing that resource.
+ """
+
+ def __init__(self, resource, new_location, exact=False):
+ self.project = resource.project
+ self.resource = resource
+ if not exact:
+ new_location = _get_destination_for_move(resource, new_location)
+ if resource.is_folder():
+ self.new_resource = self.project.get_folder(new_location)
+ else:
+ self.new_resource = self.project.get_file(new_location)
+
+ @_handle_job_set
+ def do(self):
+ self._operations.move(self.resource, self.new_resource)
+
+ @_handle_job_set
+ def undo(self):
+ self._operations.move(self.new_resource, self.resource)
+
+ def __str__(self):
+ return 'Move <%s>' % self.resource.path
+
+ def get_description(self):
+ return 'rename from %s\nrename to %s' % (self.resource.path,
+ self.new_resource.path)
+
+ def get_changed_resources(self):
+ return [self.resource, self.new_resource]
+
+
+class CreateResource(Change):
+ """A class to create a resource
+
+ Fields:
+
+ * `resource`: The resource to create
+ """
+
+ def __init__(self, resource):
+ self.resource = resource
+
+ @_handle_job_set
+ def do(self):
+ self._operations.create(self.resource)
+
+ @_handle_job_set
+ def undo(self):
+ self._operations.remove(self.resource)
+
+ def __str__(self):
+ return 'Create Resource <%s>' % (self.resource.path)
+
+ def get_description(self):
+ return 'new file %s' % (self.resource.path)
+
+ def get_changed_resources(self):
+ return [self.resource]
+
+ def _get_child_path(self, parent, name):
+ if parent.path == '':
+ return name
+ else:
+ return parent.path + '/' + name
+
+
+class CreateFolder(CreateResource):
+ """A class to create a folder
+
+ See docs for `CreateResource`.
+ """
+
+ def __init__(self, parent, name):
+ resource = parent.project.get_folder(
+ self._get_child_path(parent, name))
+ super(CreateFolder, self).__init__(resource)
+
+
+class CreateFile(CreateResource):
+ """A class to create a file
+
+ See docs for `CreateResource`.
+ """
+
+ def __init__(self, parent, name):
+ resource = parent.project.get_file(self._get_child_path(parent, name))
+ super(CreateFile, self).__init__(resource)
+
+
+class RemoveResource(Change):
+ """A class to remove a resource
+
+ Fields:
+
+ * `resource`: The resource to be removed
+ """
+
+ def __init__(self, resource):
+ self.resource = resource
+
+ @_handle_job_set
+ def do(self):
+ self._operations.remove(self.resource)
+
+ # TODO: Undoing remove operations
+ @_handle_job_set
+ def undo(self):
+ raise NotImplementedError(
+ 'Undoing `RemoveResource` is not implemented yet.')
+
+ def __str__(self):
+ return 'Remove <%s>' % (self.resource.path)
+
+ def get_changed_resources(self):
+ return [self.resource]
+
+
+def count_changes(change):
+ """Counts the number of basic changes a `Change` will make"""
+ if isinstance(change, ChangeSet):
+ result = 0
+ for child in change.changes:
+ result += count_changes(child)
+ return result
+ return 1
+
+
+def create_job_set(task_handle, change):
+ return task_handle.create_jobset(str(change), count_changes(change))
+
+
+class _ResourceOperations(object):
+
+ def __init__(self, project):
+ self.project = project
+ self.fscommands = project.fscommands
+ self.direct_commands = rope.base.fscommands.FileSystemCommands()
+
+ def _get_fscommands(self, resource):
+ if self.project.is_ignored(resource):
+ return self.direct_commands
+ return self.fscommands
+
+ def write_file(self, resource, contents):
+ data = rope.base.fscommands.unicode_to_file_data(contents)
+ fscommands = self._get_fscommands(resource)
+ fscommands.write(resource.real_path, data)
+ for observer in list(self.project.observers):
+ observer.resource_changed(resource)
+
+ def move(self, resource, new_resource):
+ fscommands = self._get_fscommands(resource)
+ fscommands.move(resource.real_path, new_resource.real_path)
+ for observer in list(self.project.observers):
+ observer.resource_moved(resource, new_resource)
+
+ def create(self, resource):
+ if resource.is_folder():
+ self._create_resource(resource.path, kind='folder')
+ else:
+ self._create_resource(resource.path)
+ for observer in list(self.project.observers):
+ observer.resource_created(resource)
+
+ def remove(self, resource):
+ fscommands = self._get_fscommands(resource)
+ fscommands.remove(resource.real_path)
+ for observer in list(self.project.observers):
+ observer.resource_removed(resource)
+
+ def _create_resource(self, file_name, kind='file'):
+ resource_path = self.project._get_resource_path(file_name)
+ if os.path.exists(resource_path):
+ raise exceptions.RopeError('Resource <%s> already exists'
+ % resource_path)
+ resource = self.project.get_file(file_name)
+ if not resource.parent.exists():
+ raise exceptions.ResourceNotFoundError(
+ 'Parent folder of <%s> does not exist' % resource.path)
+ fscommands = self._get_fscommands(resource)
+ try:
+ if kind == 'file':
+ fscommands.create_file(resource_path)
+ else:
+ fscommands.create_folder(resource_path)
+ except IOError as e:
+ raise exceptions.RopeError(e)
+
+
+def _get_destination_for_move(resource, destination):
+ dest_path = resource.project._get_resource_path(destination)
+ if os.path.isdir(dest_path):
+ if destination != '':
+ return destination + '/' + resource.name
+ else:
+ return resource.name
+ return destination
+
+
+class ChangeToData(object):
+
+ def convertChangeSet(self, change):
+ description = change.description
+ changes = []
+ for child in change.changes:
+ changes.append(self(child))
+ return (description, changes, change.time)
+
+ def convertChangeContents(self, change):
+ return (change.resource.path, change.new_contents, change.old_contents)
+
+ def convertMoveResource(self, change):
+ return (change.resource.path, change.new_resource.path)
+
+ def convertCreateResource(self, change):
+ return (change.resource.path, change.resource.is_folder())
+
+ def convertRemoveResource(self, change):
+ return (change.resource.path, change.resource.is_folder())
+
+ def __call__(self, change):
+ change_type = type(change)
+ if change_type in (CreateFolder, CreateFile):
+ change_type = CreateResource
+ method = getattr(self, 'convert' + change_type.__name__)
+ return (change_type.__name__, method(change))
+
+
+class DataToChange(object):
+
+ def __init__(self, project):
+ self.project = project
+
+ def makeChangeSet(self, description, changes, time=None):
+ result = ChangeSet(description, time)
+ for child in changes:
+ result.add_change(self(child))
+ return result
+
+ def makeChangeContents(self, path, new_contents, old_contents):
+ resource = self.project.get_file(path)
+ return ChangeContents(resource, new_contents, old_contents)
+
+ def makeMoveResource(self, old_path, new_path):
+ resource = self.project.get_file(old_path)
+ return MoveResource(resource, new_path, exact=True)
+
+ def makeCreateResource(self, path, is_folder):
+ if is_folder:
+ resource = self.project.get_folder(path)
+ else:
+ resource = self.project.get_file(path)
+ return CreateResource(resource)
+
+ def makeRemoveResource(self, path, is_folder):
+ if is_folder:
+ resource = self.project.get_folder(path)
+ else:
+ resource = self.project.get_file(path)
+ return RemoveResource(resource)
+
+ def __call__(self, data):
+ method = getattr(self, 'make' + data[0])
+ return method(*data[1])
« no previous file with comments | « tools/telemetry/third_party/rope/rope/base/builtins.py ('k') | tools/telemetry/third_party/rope/rope/base/codeanalyze.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698