From 257f751dfaa4a3086929ff68579203554f124a61 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Sat, 29 Nov 2014 22:39:44 +0200 Subject: [PATCH] Implement ApplicationState Manager --- platformio/app.py | 111 +++++++++++++++++++++++++++++++++++ platformio/exception.py | 10 ++++ platformio/pkgmanager.py | 19 +++--- platformio/platforms/base.py | 96 +++++++++++++++--------------- platformio/util.py | 23 -------- 5 files changed, 181 insertions(+), 78 deletions(-) create mode 100644 platformio/app.py diff --git a/platformio/app.py b/platformio/app.py new file mode 100644 index 00000000..3f24617a --- /dev/null +++ b/platformio/app.py @@ -0,0 +1,111 @@ +# Copyright (C) Ivan Kravets +# See LICENSE for details. + +import json +from os.path import isfile, join + +from platformio import __version__ +from platformio.exception import InvalidSettingName, InvalidSettingValue +from platformio.util import get_home_dir + +DEFAULT_SETTINGS = { + "check_platformio_interval": { + "description": "Check for the new PlatformIO interval (days)", + "value": 3 + }, + "check_platforms_interval": { + "description": "Check for the platform updates interval (days)", + "value": 7 + }, + "check_libraries_interval": { + "description": "Check for the library updates interval (days)", + "value": 7 + }, + "auto_update_platforms": { + "description": "Automatically update platforms (Yes/No)", + "value": True + }, + "auto_update_libraries": { + "description": "Automatically update libraries (Yes/No)", + "value": True + }, + "enable_telemetry": { + "description": ("Shares commands, platforms and libraries usage" + " to help us make PlatformIO better (Yes/No)"), + "value": True + } +} + + +class State(object): + + def __init__(self, path=None): + self.path = path + if not self.path: + self.path = join(get_home_dir(), "appstate.json") + self._state = {} + + def __enter__(self): + try: + if isfile(self.path): + with open(self.path, "r") as fp: + self._state = json.load(fp) + except ValueError: + self._state = {} + return self._state + + def __exit__(self, type_, value, traceback): + with open(self.path, "w") as fp: + if "dev" in __version__: + json.dump(self._state, fp, indent=4) + else: + json.dump(self._state, fp) + + +def get_state_item(name, default=None): + with State() as data: + return data.get(name, default) + + +def set_state_item(name, value): + with State() as data: + data[name] = value + + +def get_setting(name): + if name not in DEFAULT_SETTINGS: + raise InvalidSettingName(name) + + with State() as data: + if "settings" in data and name in data['settings']: + return data['settings'][name] + + return DEFAULT_SETTINGS[name]['value'] + + +def set_setting(name, value): + if name not in DEFAULT_SETTINGS: + raise InvalidSettingName(name) + + defdata = DEFAULT_SETTINGS[name] + try: + if "validator" in defdata: + value = defdata['validator']() + elif (isinstance(defdata['value'], bool) + and not isinstance(value, bool)): + value = str(value).lower() in ("yes", "y", "1") + elif isinstance(defdata['value'], int): + value = int(value) + except Exception: + raise InvalidSettingValue(value, name) + + with State() as data: + if "settings" not in data: + data['settings'] = {} + data['settings'][name] = value + + +def reset_settings(): + with State() as data: + if "settings" in data: + del data['settings'] diff --git a/platformio/exception.py b/platformio/exception.py index 48c12d94..3d8c4494 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -129,3 +129,13 @@ class LibInstallDependencyError(PlatformioException): class BuildScriptNotFound(PlatformioException): MESSAGE = "Invalid path '%s' to build script" + + +class InvalidSettingName(PlatformioException): + + MESSAGE = "Invalid setting with the name '%s'" + + +class InvalidSettingValue(PlatformioException): + + MESSAGE = "Invalid value '%s' for the setting '%s'" diff --git a/platformio/pkgmanager.py b/platformio/pkgmanager.py index 4dedaed9..b5df5bdf 100644 --- a/platformio/pkgmanager.py +++ b/platformio/pkgmanager.py @@ -8,11 +8,13 @@ from time import time from click import echo, secho, style +from platformio import telemetry +from platformio.app import get_state_item, set_state_item from platformio.downloader import FileDownloader from platformio.exception import (InvalidPackageVersion, NonSystemPackage, UnknownPackage) from platformio.unpacker import FileUnpacker -from platformio.util import AppState, get_api_result, get_home_dir, get_systype +from platformio.util import get_api_result, get_home_dir, get_systype class PackageManager(object): @@ -47,15 +49,14 @@ class PackageManager(object): @staticmethod def get_installed(): - pkgs = {} - with AppState() as state: - pkgs = state.get("installed_packages", {}) - return pkgs + return get_state_item("installed_packages", {}) - @staticmethod - def update_appstate_instpkgs(data): - with AppState() as state: - state['installed_packages'] = data + def get_outdated(self): + outdated = [] + for name, data in self.get_installed().items(): + if data['version'] != self.get_info(name)['version']: + outdated.append(name) + return outdated def is_installed(self, name): return name in self.get_installed() diff --git a/platformio/platforms/base.py b/platformio/platforms/base.py index 91f782a4..03ef4b38 100644 --- a/platformio/platforms/base.py +++ b/platformio/platforms/base.py @@ -3,13 +3,13 @@ from imp import load_source from os import listdir -from os.path import isfile, join +from os.path import isdir, isfile, join +from platformio.app import get_state_item, set_state_item from platformio.exception import (BuildScriptNotFound, PlatformNotInstalledYet, UnknownPackage, UnknownPlatform) from platformio.pkgmanager import PackageManager -from platformio.util import (AppState, exec_command, get_home_dir, - get_source_dir) +from platformio.util import exec_command, get_home_dir, get_source_dir class PlatformFactory(object): @@ -18,36 +18,6 @@ class PlatformFactory(object): def get_clsname(name): return "%sPlatform" % name.title() - @staticmethod - def get_platforms(installed=False): - platforms = {} - for d in (get_home_dir(), get_source_dir()): - pdir = join(d, "platforms") - for p in listdir(pdir): - if p in ("__init__.py", "base.py") or not p.endswith(".py"): - continue - name = p[:-3] - path = join(pdir, p) - try: - isplatform = hasattr( - PlatformFactory.load_module(name, path), - PlatformFactory.get_clsname(name) - ) - if isplatform: - platforms[name] = path - except UnknownPlatform: - pass - - if not installed: - return platforms - - installed_platforms = {} - with AppState() as state: - for name in state.get("installed_platforms", []): - if name in platforms: - installed_platforms[name] = platforms[name] - return installed_platforms - @staticmethod def load_module(name, path): module = None @@ -58,15 +28,46 @@ class PlatformFactory(object): raise UnknownPlatform(name) return module - @staticmethod - def newPlatform(name): - platforms = PlatformFactory.get_platforms() + @classmethod + def get_platforms(cls, installed=False): + platforms = {} + for d in (get_home_dir(), get_source_dir()): + pdir = join(d, "platforms") + if not isdir(pdir): + continue + for p in listdir(pdir): + if p in ("__init__.py", "base.py") or not p.endswith(".py"): + continue + name = p[:-3] + path = join(pdir, p) + try: + isplatform = hasattr( + cls.load_module(name, path), + cls.get_clsname(name) + ) + if isplatform: + platforms[name] = path + except UnknownPlatform: + pass + + if not installed: + return platforms + + installed_platforms = {} + for name in get_state_item("installed_platforms", []): + if name in platforms: + installed_platforms[name] = platforms[name] + return installed_platforms + + @classmethod + def newPlatform(cls, name): + platforms = cls.get_platforms() if name not in platforms: raise UnknownPlatform(name) _instance = getattr( - PlatformFactory.load_module(name, platforms[name]), - PlatformFactory.get_clsname(name) + cls.load_module(name, platforms[name]), + cls.get_clsname(name) )() assert isinstance(_instance, BasePlatform) return _instance @@ -137,11 +138,10 @@ class BasePlatform(object): pm.install(name) # register installed platform - with AppState() as state: - data = state.get("installed_platforms", []) - if self.get_name() not in data: - data.append(self.get_name()) - state['installed_platforms'] = data + data = get_state_item("installed_platforms", []) + if self.get_name() not in data: + data.append(self.get_name()) + set_state_item("installed_platforms", data) return len(requirements) @@ -167,9 +167,8 @@ class BasePlatform(object): pm.uninstall(name) # unregister installed platform - with AppState() as state: - installed_platforms.remove(platform) - state['installed_platforms'] = installed_platforms + installed_platforms.remove(platform) + set_state_item("installed_platforms", installed_platforms) return True @@ -178,6 +177,11 @@ class BasePlatform(object): for name in self.get_installed_packages(): pm.update(name) + def is_outdated(self): + pm = PackageManager() + obsolated = pm.get_outdated() + return not set(self.get_packages().keys()).isdisjoint(set(obsolated)) + def run(self, variables, targets): assert isinstance(variables, list) assert isinstance(targets, list) diff --git a/platformio/util.py b/platformio/util.py index 66e63606..b7cc284a 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -1,7 +1,6 @@ # Copyright (C) Ivan Kravets # See LICENSE for details. -import json from os import name as os_name from os import getcwd, getenv, makedirs, utime from os.path import dirname, expanduser, isdir, isfile, join, realpath @@ -22,28 +21,6 @@ except ImportError: from ConfigParser import ConfigParser -class AppState(object): - - def __init__(self, path=None): - self.path = path - if not self.path: - self.path = join(get_home_dir(), "appstate.json") - self._state = {} - - def __enter__(self): - try: - if isfile(self.path): - with open(self.path, "r") as fp: - self._state = json.load(fp) - except ValueError: - self._state = {} - return self._state - - def __exit__(self, type_, value, traceback): - with open(self.path, "w") as fp: - json.dump(self._state, fp, indent=4) - - def get_systype(): if system() == "Windows": return "windows"