Skip to content
Snippets Groups Projects
Commit 16536fe4 authored by q3k's avatar q3k Committed by q3k
Browse files

py: load bundles from /sd/apps and /flash/apps

parent 971a008b
Branches
Tags
1 merge request!188Q3k/fancy 1.2 features
...@@ -6,7 +6,7 @@ from st3m.ui.view import ( ...@@ -6,7 +6,7 @@ from st3m.ui.view import (
) )
from st3m.ui.menu import MenuItem from st3m.ui.menu import MenuItem
from st3m.input import InputState from st3m.input import InputState
from st3m.goose import Optional, List, Enum from st3m.goose import Optional, List, Enum, Dict
from st3m.logging import Log from st3m.logging import Log
import toml import toml
...@@ -97,7 +97,7 @@ class BundleMetadata: ...@@ -97,7 +97,7 @@ class BundleMetadata:
This data is used to discover bundles and load them as applications. This data is used to discover bundles and load them as applications.
""" """
__slots__ = ["path", "name", "menu", "_t"] __slots__ = ["path", "name", "menu", "_t", "version"]
def __init__(self, path: str) -> None: def __init__(self, path: str) -> None:
self.path = path.rstrip("/") self.path = path.rstrip("/")
...@@ -126,6 +126,11 @@ class BundleMetadata: ...@@ -126,6 +126,11 @@ class BundleMetadata:
if self.menu not in ["Apps", "Music", "Badge", "Hidden"]: if self.menu not in ["Apps", "Music", "Badge", "Hidden"]:
raise BundleMetadataBroken("app.menu must be either Apps, Music or Badge") raise BundleMetadataBroken("app.menu must be either Apps, Music or Badge")
version = 0
if t.get("metadata") is not None:
version = t["metadata"].get("version", 0)
self.version = version
self._t = t self._t = t
@staticmethod @staticmethod
...@@ -193,8 +198,16 @@ class BundleMetadata: ...@@ -193,8 +198,16 @@ class BundleMetadata:
return [] return []
return [MenuItemAppLaunch(self)] return [MenuItemAppLaunch(self)]
@property
def source(self) -> str:
return os.path.dirname(self.path)
@property
def id(self) -> str:
return os.path.basename(self.path)
def __repr__(self) -> str: def __repr__(self) -> str:
return f"<BundleMetadata: {self.name} at {self.path}>" return f"<BundleMetadata: {self.id} at {self.path}>"
class MenuItemAppLaunch(MenuItem): class MenuItemAppLaunch(MenuItem):
...@@ -226,6 +239,80 @@ class MenuItemAppLaunch(MenuItem): ...@@ -226,6 +239,80 @@ class MenuItemAppLaunch(MenuItem):
return self._bundle.name return self._bundle.name
class BundleManager:
"""
The BundleManager maintains information about BundleMetadata at different
locations in the badge filesystem.
It also manages updating/reloading bundles.
"""
def __init__(self) -> None:
self.bundles: Dict[str, BundleMetadata] = {}
@staticmethod
def _source_trumps(a: str, b: str) -> bool:
prios = {
"/flash/sys/apps": 200,
"/sd/apps": 120,
"/flash/apps": 100,
}
prio_a = prios.get(a, 0)
prio_b = prios.get(b, 0)
return prio_a > prio_b
def _discover_at(self, path: str) -> None:
path = path.rstrip("/")
try:
l = os.listdir(path)
except Exception as e:
log.warning(f"Could not discover bundles in {path}: {e}")
l = []
for d in l:
dirpath = path + "/" + d
st = os.stat(dirpath)
if not stat.S_ISDIR(st[0]):
continue
tomlpath = dirpath + "/flow3r.toml"
try:
st = os.stat(tomlpath)
if not stat.S_ISREG(st[0]):
continue
except Exception:
continue
try:
b = BundleMetadata(dirpath)
except BundleLoadException as e:
log.error(f"Failed to bundle from {dirpath}: {e}")
continue
id_ = b.id
if id_ not in self.bundles:
self.bundles[id_] = b
continue
ex = self.bundles[id_]
# Do we have a newer version?
if b.version > ex.version:
self.bundles[id_] = b
continue
# Do we have a higher priority source?
if self._source_trumps(b.source, ex.source):
self.bundles[id_] = b
continue
log.warning(
f"Ignoring {id_} at {b.source} as it already exists at {ex.source}"
)
def update(self) -> None:
self._discover_at("/flash/sys/apps")
self._discover_at("/flash/apps")
self._discover_at("/sd/apps")
def discover_bundles(path: str) -> List[BundleMetadata]: def discover_bundles(path: str) -> List[BundleMetadata]:
""" """
Discover valid bundles (directories containing flow3r.toml) inside a given Discover valid bundles (directories containing flow3r.toml) inside a given
......
...@@ -11,7 +11,7 @@ from st3m.ui.menu import ( ...@@ -11,7 +11,7 @@ from st3m.ui.menu import (
from st3m.ui.elements import overlays from st3m.ui.elements import overlays
from st3m.ui.view import View, ViewManager, ViewTransitionBlend from st3m.ui.view import View, ViewManager, ViewTransitionBlend
from st3m.ui.elements.menus import SimpleMenu, SunMenu from st3m.ui.elements.menus import SimpleMenu, SunMenu
from st3m.application import discover_bundles, BundleMetadata, MenuItemAppLaunch from st3m.application import BundleManager, BundleMetadata, MenuItemAppLaunch
from st3m.about import About from st3m.about import About
from st3m import settings, logging, processors, wifi from st3m import settings, logging, processors, wifi
...@@ -52,9 +52,11 @@ def run_responder(r: Responder) -> None: ...@@ -52,9 +52,11 @@ def run_responder(r: Responder) -> None:
reactor.run() reactor.run()
def _make_bundle_menu(bundles: List[BundleMetadata], kind: str) -> SimpleMenu: def _make_bundle_menu(mgr: BundleManager, kind: str) -> SimpleMenu:
entries: List[MenuItem] = [MenuItemBack()] entries: List[MenuItem] = [MenuItemBack()]
for bundle in bundles: ids = sorted(mgr.bundles.keys())
for id in ids:
bundle = mgr.bundles[id]
entries += bundle.menu_entries(kind) entries += bundle.menu_entries(kind)
return SimpleMenu(entries) return SimpleMenu(entries)
...@@ -127,7 +129,8 @@ def run_main() -> None: ...@@ -127,7 +129,8 @@ def run_main() -> None:
audio.set_volume_dB(-10) audio.set_volume_dB(-10)
leds.set_rgb(0, 255, 0, 0) leds.set_rgb(0, 255, 0, 0)
leds.update() leds.update()
bundles = discover_bundles("/flash/sys/apps") bundles = BundleManager()
bundles.update()
settings.load_all() settings.load_all()
menu_settings = settings.build_menu() menu_settings = settings.build_menu()
...@@ -152,8 +155,7 @@ def run_main() -> None: ...@@ -152,8 +155,7 @@ def run_main() -> None:
], ],
) )
if override_main_app is not None: if override_main_app is not None:
requested = [b for b in bundles if b.name == override_main_app] requested = [b for b in bundles.bundles.values() if b.name == override_main_app]
print([b.name for b in bundles])
if len(requested) > 1: if len(requested) > 1:
raise Exception(f"More than one bundle named {override_main_app}") raise Exception(f"More than one bundle named {override_main_app}")
if len(requested) == 0: if len(requested) == 0:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment