Implement ApplicationState Manager

This commit is contained in:
Ivan Kravets
2014-11-29 22:39:44 +02:00
parent e41226fcbc
commit 257f751dfa
5 changed files with 181 additions and 78 deletions

111
platformio/app.py Normal file
View File

@ -0,0 +1,111 @@
# Copyright (C) Ivan Kravets <me@ikravets.com>
# 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']

View File

@ -129,3 +129,13 @@ class LibInstallDependencyError(PlatformioException):
class BuildScriptNotFound(PlatformioException): class BuildScriptNotFound(PlatformioException):
MESSAGE = "Invalid path '%s' to build script" 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'"

View File

@ -8,11 +8,13 @@ from time import time
from click import echo, secho, style 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.downloader import FileDownloader
from platformio.exception import (InvalidPackageVersion, NonSystemPackage, from platformio.exception import (InvalidPackageVersion, NonSystemPackage,
UnknownPackage) UnknownPackage)
from platformio.unpacker import FileUnpacker 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): class PackageManager(object):
@ -47,15 +49,14 @@ class PackageManager(object):
@staticmethod @staticmethod
def get_installed(): def get_installed():
pkgs = {} return get_state_item("installed_packages", {})
with AppState() as state:
pkgs = state.get("installed_packages", {})
return pkgs
@staticmethod def get_outdated(self):
def update_appstate_instpkgs(data): outdated = []
with AppState() as state: for name, data in self.get_installed().items():
state['installed_packages'] = data if data['version'] != self.get_info(name)['version']:
outdated.append(name)
return outdated
def is_installed(self, name): def is_installed(self, name):
return name in self.get_installed() return name in self.get_installed()

View File

@ -3,13 +3,13 @@
from imp import load_source from imp import load_source
from os import listdir 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, from platformio.exception import (BuildScriptNotFound, PlatformNotInstalledYet,
UnknownPackage, UnknownPlatform) UnknownPackage, UnknownPlatform)
from platformio.pkgmanager import PackageManager from platformio.pkgmanager import PackageManager
from platformio.util import (AppState, exec_command, get_home_dir, from platformio.util import exec_command, get_home_dir, get_source_dir
get_source_dir)
class PlatformFactory(object): class PlatformFactory(object):
@ -18,36 +18,6 @@ class PlatformFactory(object):
def get_clsname(name): def get_clsname(name):
return "%sPlatform" % name.title() 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 @staticmethod
def load_module(name, path): def load_module(name, path):
module = None module = None
@ -58,15 +28,46 @@ class PlatformFactory(object):
raise UnknownPlatform(name) raise UnknownPlatform(name)
return module return module
@staticmethod @classmethod
def newPlatform(name): def get_platforms(cls, installed=False):
platforms = PlatformFactory.get_platforms() 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: if name not in platforms:
raise UnknownPlatform(name) raise UnknownPlatform(name)
_instance = getattr( _instance = getattr(
PlatformFactory.load_module(name, platforms[name]), cls.load_module(name, platforms[name]),
PlatformFactory.get_clsname(name) cls.get_clsname(name)
)() )()
assert isinstance(_instance, BasePlatform) assert isinstance(_instance, BasePlatform)
return _instance return _instance
@ -137,11 +138,10 @@ class BasePlatform(object):
pm.install(name) pm.install(name)
# register installed platform # register installed platform
with AppState() as state: data = get_state_item("installed_platforms", [])
data = state.get("installed_platforms", [])
if self.get_name() not in data: if self.get_name() not in data:
data.append(self.get_name()) data.append(self.get_name())
state['installed_platforms'] = data set_state_item("installed_platforms", data)
return len(requirements) return len(requirements)
@ -167,9 +167,8 @@ class BasePlatform(object):
pm.uninstall(name) pm.uninstall(name)
# unregister installed platform # unregister installed platform
with AppState() as state:
installed_platforms.remove(platform) installed_platforms.remove(platform)
state['installed_platforms'] = installed_platforms set_state_item("installed_platforms", installed_platforms)
return True return True
@ -178,6 +177,11 @@ class BasePlatform(object):
for name in self.get_installed_packages(): for name in self.get_installed_packages():
pm.update(name) 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): def run(self, variables, targets):
assert isinstance(variables, list) assert isinstance(variables, list)
assert isinstance(targets, list) assert isinstance(targets, list)

View File

@ -1,7 +1,6 @@
# Copyright (C) Ivan Kravets <me@ikravets.com> # Copyright (C) Ivan Kravets <me@ikravets.com>
# See LICENSE for details. # See LICENSE for details.
import json
from os import name as os_name from os import name as os_name
from os import getcwd, getenv, makedirs, utime from os import getcwd, getenv, makedirs, utime
from os.path import dirname, expanduser, isdir, isfile, join, realpath from os.path import dirname, expanduser, isdir, isfile, join, realpath
@ -22,28 +21,6 @@ except ImportError:
from ConfigParser import ConfigParser 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(): def get_systype():
if system() == "Windows": if system() == "Windows":
return "windows" return "windows"