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):
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 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()

View File

@ -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)

View File

@ -1,7 +1,6 @@
# Copyright (C) Ivan Kravets <me@ikravets.com>
# 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"