Mon, 11 Sep 2017 19:55:45 +0200
Implemented the distributed rope file system commands.
# -*- coding: utf-8 -*- # Copyright (c) 2017 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing the refactoring client interface to rope. """ from __future__ import unicode_literals import sys import os sys.path.insert(0, os.path.dirname(__file__)) if sys.version_info[0] >= 3: path = os.path.join(os.path.dirname(__file__), 'rope_py3') else: path = os.path.join(os.path.dirname(__file__), 'rope_py2') sys.path.insert(0, path) try: bytes = unicode import StringIO as io # __IGNORE_EXCEPTION__ except NameError: import io # __IGNORE_WARNING__ import socket import select import traceback import time import json import rope.base.project class RefactoringClient(object): """ Class implementing the refactoring client interface to rope. """ def __init__(self, host, port, projectPath): """ Constructor @param host ip address the background service is listening @type str @param port port of the background service @type int @param projectPath path to the project @type str """ self.__connection = socket.create_connection((host, port)) from FileSystemCommands import RefactoringClientFileSystemCommands self.__fsCommands = RefactoringClientFileSystemCommands(self) self.__projectpath = projectPath self.__project = rope.base.project.Project( self.__projectpath, fscommands=self.__fsCommands) def __processJson(self, jsonStr): """ Public method to handle a command serialized as a JSON string. @param jsonStr string containing the command received from the IDE @type str """ try: commandDict = json.loads(jsonStr.strip()) except (TypeError, ValueError) as err: self.sendJson("ClientException", { "ExceptionType": "ProtocolError", "ExceptionValue": str(err), "ProtocolData": jsonStr.strip(), }) return method = commandDict["method"] params = commandDict["params"] if "filename" in params and sys.version_info[0] == 2: params["filename"] = params["filename"].encode( sys.getfilesystemencoding()) if method == "ping": self.sendJson("pong", {}) def sendJson(self, command, params): """ Public method to send a single refactoring command to the client. @param command command name to be sent @type str @param params dictionary of named parameters for the command @type dict """ import json commandDict = { "jsonrpc": "2.0", "method": command, "params": params, } cmd = json.dumps(commandDict) + '\n' self.__connection.sendall(cmd.encode('utf8', 'backslashreplace')) def __receiveJson(self): """ Private method to receive a JSON encode command and data from the server. """ line = self.__connection.recv(1024 * 1024, socket.MSG_PEEK) # 1M buffer eol = line.find(b'\n') if eol >= 0: size = eol + 1 # Now we know how big the line is, read it for real. line = self.__connection.recv(size).decode( 'utf8', 'backslashreplace') self.__processJson(line) def run(self): """ Public method implementing the main loop of the client. """ try: while True: try: rrdy, wrdy, xrdy = select.select( [self.__connection], [], []) except (select.error, KeyboardInterrupt, socket.error): # just carry on continue if self.__connection in rrdy: self.__receiveJson() except Exception: exctype, excval, exctb = sys.exc_info() tbinfofile = io.StringIO() traceback.print_tb(exctb, None, tbinfofile) tbinfofile.seek(0) tbinfo = tbinfofile.read() del exctb self.sendJson("ClientException", { "ExceptionType": str(exctype), "ExceptionValue": str(excval), "Traceback": tbinfo, }) # Give time to process latest response on server side time.sleep(0.5) self.__connection.shutdown(socket.SHUT_RDWR) self.__connection.close() if __name__ == '__main__': if len(sys.argv) != 4: print('Host, port and project path parameters are missing. Abort.') sys.exit(1) host, port, projectPath = sys.argv[1:] client = RefactoringClient(host, int(port), projectPath) # Start the main loop client.run() # # eflag: noqa = M801