mirror of
https://github.com/platformio/platformio-core.git
synced 2025-07-29 17:47:14 +02:00
Implement ApplicationState Manager
This commit is contained in:
111
platformio/app.py
Normal file
111
platformio/app.py
Normal 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']
|
@ -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'"
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
Reference in New Issue
Block a user