PackageManager: add dictionary for easy package lookup

This commit is contained in:
Thomas Farstrike
2025-10-29 23:40:05 +01:00
parent 73497d8aa2
commit cea4e59341
2 changed files with 84 additions and 29 deletions
@@ -312,7 +312,7 @@ class AppDetail(Activity):
print("Uninstalling app....")
try:
_thread.stack_size(mpos.apps.good_stack_size())
_thread.start_new_thread(self.uninstall_app, (fullname))
_thread.start_new_thread(self.uninstall_app, (fullname,))
except Exception as e:
print("Could not start uninstall_app thread: ", e)
@@ -349,7 +349,7 @@ class AppDetail(Activity):
try:
# Step 1: Download the .mpk file
print(f"Downloading .mpk file from: {zip_url}")
response = requests.get(zip_url, timeout=10)
response = requests.get(zip_url, timeout=10) # TODO: use stream=True and do it in chunks like in OSUpdate
if response.status_code != 200:
print("Download failed: Status code", response.status_code)
response.close()
+82 -27
View File
@@ -28,50 +28,105 @@ Question: does it make sense to cache the database?
'''
# PackageManager.py (MicroPython)
class PackageManager():
import os
app_list = [] # list of App objects, sorted alphabetically by app.name, unique by full_name (com.example.appname)
class PackageManager:
"""Registry of all discovered apps.
* PackageManager.get_app_list() -> list of App objects (sorted by name)
* PackageManager[fullname] -> App (raises KeyError if missing)
* PackageManager.get(fullname) -> App or None
"""
# --------------------------------------------------------------------- #
# internal storage
# --------------------------------------------------------------------- #
_app_list = [] # sorted by app.name
_by_fullname = {} # fullname -> App
# --------------------------------------------------------------------- #
# public list access (kept for backward compatibility)
# --------------------------------------------------------------------- #
@classmethod
def get_app_list(cls):
if len(cls.app_list) == 0:
if not cls._app_list:
cls.find_apps()
return cls.app_list
return cls._app_list
# --------------------------------------------------------------------- #
# dict-style lookup: PackageManager["com.example.myapp"]
# --------------------------------------------------------------------- #
def __class_getitem__(cls, fullname):
try:
return cls._by_fullname[fullname]
except KeyError:
raise KeyError("No app with fullname='{}'".format(fullname))
# --------------------------------------------------------------------- #
# safe lookup: PackageManager.get("com.example.myapp") -> App or None
# --------------------------------------------------------------------- #
@classmethod
def get(cls, fullname):
return cls._by_fullname.get(fullname)
# --------------------------------------------------------------------- #
# discovery & population
# --------------------------------------------------------------------- #
@classmethod
def find_apps(cls):
print("\n\n\nPackageManager finding apps...")
seen_fullnames = set()
# Check and collect subdirectories from existing directories
apps_dir = "apps"
seen = set() # avoid processing the same fullname twice
apps_dir = "apps"
apps_dir_builtin = "builtin/apps"
# Check and collect unique subdirectories
for dir_path in [apps_dir, apps_dir_builtin]:
for base in (apps_dir, apps_dir_builtin):
try:
if os.stat(dir_path)[0] & 0x4000: # Verify directory exists
# ---- does the directory exist? --------------------------------
st = os.stat(base)
if not (st[0] & 0x4000): # 0x4000 = directory bit
continue
# ---- iterate over immediate children -------------------------
for name in os.listdir(base):
full_path = "{}/{}".format(base, name)
# ---- is it a directory? ---------------------------------
try:
for d in os.listdir(dir_path):
full_path = f"{dir_path}/{d}"
print(f"full_path: {full_path}")
try:
if os.stat(full_path)[0] & 0x4000: # Check if it's a directory
fullname = d
if fullname not in seen_fullnames: # Avoid duplicates
seen_fullnames.add(fullname)
app = mpos.apps.parse_manifest(full_path)
cls.app_list.append(app)
print(f"added app {app}")
except Exception as e:
print(f"PackageManager: stat of {full_path} got exception: {e}")
st = os.stat(full_path)
if not (st[0] & 0x4000):
continue
except Exception as e:
print(f"PackageManager: listdir of {dir_path} got exception: {e}")
print("PackageManager: stat of {} got exception: {}".format(full_path, e))
continue
fullname = name
# ---- skip duplicates ------------------------------------
if fullname in seen:
continue
seen.add(fullname)
# ---- parse the manifest ---------------------------------
try:
app = mpos.apps.parse_manifest(full_path)
except Exception as e:
print("PackageManager: parsing {} failed: {}".format(full_path, e))
continue
# ---- store in both containers ---------------------------
cls._app_list.append(app)
cls._by_fullname[fullname] = app
print("added app {}".format(app))
except Exception as e:
print(f"PackageManager: stat of {dir_path} got exception: {e}")
print("PackageManager: handling {} got exception: {}".format(base, e))
# ---- sort the list by display name (case-insensitive) ------------
cls._app_list.sort(key=lambda a: a.name.lower())
# Sort apps alphabetically by app.name
cls.app_list.sort(key=lambda x: x.name.lower()) # Case-insensitive sorting by name
@staticmethod
def uninstall_app(app_fullname):