mirror of
https://github.com/platformio/platformio-core.git
synced 2025-07-31 10:37:13 +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):
|
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'"
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
|
@ -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"
|
||||||
|
Reference in New Issue
Block a user