class MoveFSItemOperation(FSOperationBase): """Move a file or directory to the given name""" __slots__ = ("_source_path", "_destination_path", "_actual_destination_path") name = "FSItemMove" def __init__(self, transaction, source_path, destination_path): super(MoveFSItemOperation, self).__init__(transaction) self._source_path = Path(source_path).expandvars() self._destination_path = self._actual_destination_path = Path(destination_path).expandvars() # if we move into a directory, the filename will just be appended if self._destination_path.isdir(): self._actual_destination_path = self._destination_path / source_path.basename() # END handle actual destination def apply(self): if self._actual_destination_path.exists(): raise AssertionError("Cannot move item %s onto existing one at %s" % (self._source_path, self._actual_destination_path)) # END handle existing dsetination if self._dry_run(): return self.log.info("moving %s to %s", self._source_path, self._destination_path) self._source_path.move(self._destination_path) self._operation_performed = True def rollback(self): try: if not self._operation_performed or not self._actual_destination_path.exists(): return # fail gracefully if self._source_path.exists(): raise AssertionError("Cannot move destination %s into existing source %s, source directory should not exist" % ( self._actual_destination_path, self._source_path)) self.log.info("moving %s to %s", self._actual_destination_path, self._source_path) self._actual_destination_path.move(self._source_path) finally: self._reset_state() # END assure state reset #{ Interface def actual_destination(self): """:return: path to the final destination""" return self._actual_destination_path