From d2c86ab71c4bb1ecae9a710e092358cc1e467ee0 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 2 Jul 2019 00:41:47 +0300 Subject: [PATCH] Refactor state to a proxied dictionary --- platformio/app.py | 51 +++++++++++++------ platformio/commands/home/rpc/handlers/app.py | 4 +- .../commands/home/rpc/handlers/piocore.py | 17 ++++--- platformio/commands/home/rpc/server.py | 3 +- 4 files changed, 50 insertions(+), 25 deletions(-) diff --git a/platformio/app.py b/platformio/app.py index 12dcbb41..a6fd6e45 100644 --- a/platformio/app.py +++ b/platformio/app.py @@ -14,7 +14,6 @@ import codecs import hashlib -import json import os import uuid from os import environ, getenv, listdir, remove @@ -93,29 +92,26 @@ class State(object): self.lock = lock if not self.path: self.path = join(get_project_core_dir(), "appstate.json") - self._state = {} - self._prev_state_raw = "" + self._storage = {} self._lockfile = None + self._modified = False def __enter__(self): try: self._lock_state_file() if isfile(self.path): - with open(self.path) as fp: - self._prev_state_raw = fp.read().strip() - self._state = json.loads(self._prev_state_raw) - assert isinstance(self._state, dict) - except (AssertionError, ValueError, UnicodeDecodeError): - self._state = {} - self._prev_state_raw = "" - return self._state + self._storage = util.load_json(self.path) + assert isinstance(self._storage, dict) + except (AssertionError, ValueError, UnicodeDecodeError, + exception.InvalidJSONFile): + self._storage = {} + return self def __exit__(self, type_, value, traceback): - new_state_raw = dump_json_to_unicode(self._state) - if self._prev_state_raw != new_state_raw: + if self._modified: try: with open(self.path, "w") as fp: - fp.write(new_state_raw) + fp.write(dump_json_to_unicode(self._storage)) except IOError: raise exception.HomeDirPermissionsError(get_project_core_dir()) self._unlock_state_file() @@ -133,8 +129,31 @@ class State(object): if hasattr(self, "_lockfile") and self._lockfile: self._lockfile.release() - def __del__(self): - self._unlock_state_file() + # Dictionary Proxy + + def as_dict(self): + return self._storage + + def get(self, key, default=True): + return self._storage.get(key, default) + + def update(self, *args, **kwargs): + self._modified = True + return self._storage.update(*args, **kwargs) + + def __getitem__(self, key): + return self._storage[key] + + def __setitem__(self, key, value): + self._modified = True + self._storage[key] = value + + def __delitem__(self, key): + self._modified = True + del self._storage[key] + + def __contains__(self, item): + return item in self._storage class ContentCache(object): diff --git a/platformio/commands/home/rpc/handlers/app.py b/platformio/commands/home/rpc/handlers/app.py index 0f8b8285..1666dc17 100644 --- a/platformio/commands/home/rpc/handlers/app.py +++ b/platformio/commands/home/rpc/handlers/app.py @@ -57,7 +57,7 @@ class AppRPC(object): ] state['storage'] = storage - return state + return state.as_dict() @staticmethod def get_state(): @@ -66,6 +66,6 @@ class AppRPC(object): @staticmethod def save_state(state): with app.State(AppRPC.APPSTATE_PATH, lock=True) as s: - s.clear() + # s.clear() s.update(state) return True diff --git a/platformio/commands/home/rpc/handlers/piocore.py b/platformio/commands/home/rpc/handlers/piocore.py index 4370b5a9..62dfdd3e 100644 --- a/platformio/commands/home/rpc/handlers/piocore.py +++ b/platformio/commands/home/rpc/handlers/piocore.py @@ -17,7 +17,6 @@ from __future__ import absolute_import import json import os import sys -import thread from io import BytesIO import jsonrpc # pylint: disable=import-error @@ -26,6 +25,11 @@ from twisted.internet import threads # pylint: disable=import-error from platformio import __main__, __version__, util from platformio.compat import string_types +try: + from thread import get_ident as thread_get_ident +except ImportError: + from threading import get_ident as thread_get_ident + class ThreadSafeStdBuffer(object): @@ -35,19 +39,20 @@ class ThreadSafeStdBuffer(object): self._buffer = {} def write(self, value): - thread_id = thread.get_ident() + thread_id = thread_get_ident() if thread_id == self.parent_thread_id: - return self.parent_stream.write(value) + return self.parent_stream.write( + value if isinstance(value, string_types) else value.decode()) if thread_id not in self._buffer: self._buffer[thread_id] = BytesIO() return self._buffer[thread_id].write(value) def flush(self): return (self.parent_stream.flush() - if thread.get_ident() == self.parent_thread_id else None) + if thread_get_ident() == self.parent_thread_id else None) def getvalue_and_close(self, thread_id=None): - thread_id = thread_id or thread.get_ident() + thread_id = thread_id or thread_get_ident() if thread_id not in self._buffer: return "" result = self._buffer.get(thread_id).getvalue() @@ -59,7 +64,7 @@ class ThreadSafeStdBuffer(object): class PIOCoreRPC(object): def __init__(self): - cur_thread_id = thread.get_ident() + cur_thread_id = thread_get_ident() PIOCoreRPC.thread_stdout = ThreadSafeStdBuffer(sys.stdout, cur_thread_id) PIOCoreRPC.thread_stderr = ThreadSafeStdBuffer(sys.stderr, diff --git a/platformio/commands/home/rpc/server.py b/platformio/commands/home/rpc/server.py index b77e1b94..36aa1dff 100644 --- a/platformio/commands/home/rpc/server.py +++ b/platformio/commands/home/rpc/server.py @@ -53,11 +53,12 @@ class JSONRPCServerProtocol(WebSocketServerProtocol): message=failure.getErrorMessage()) del response["result"] response['error'] = e.error._data # pylint: disable=protected-access - click.secho(str(response['error']), fg="red", err=True) self.sendJSONResponse(response) def sendJSONResponse(self, response): # click.echo("< %s" % response) + if "error" in response: + click.secho("Error: %s" % response['error'], fg="red", err=True) response = dump_json_to_unicode(response) if not PY2 and not is_bytes(response): response = response.encode("utf-8")