init
This commit is contained in:
commit
38355d2442
9083 changed files with 1225834 additions and 0 deletions
453
.venv/lib/python3.8/site-packages/rope/base/change.py
Normal file
453
.venv/lib/python3.8/site-packages/rope/base/change.py
Normal file
|
|
@ -0,0 +1,453 @@
|
|||
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`
|
||||
|
||||
A decorator for handling `taskhandle.JobSet` for `do` and `undo`
|
||||
methods of `Change`.
|
||||
"""
|
||||
|
||||
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,
|
||||
newlines=resource.newlines,
|
||||
)
|
||||
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])
|
||||
Loading…
Add table
Add a link
Reference in a new issue