Skip to content

Commit 5f1c4f1

Browse files
Improve instrumentation
1 parent 1b7a34e commit 5f1c4f1

2 files changed

Lines changed: 90 additions & 2 deletions

File tree

scripts/mpos_controller.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ def main():
776776
parser = argparse.ArgumentParser(description="MicroPythonOS Controller")
777777
parser.add_argument(
778778
"action", nargs="?", default="exec",
779-
help="Action: exec, eval, screenshot, startapp, freespace, backscreen (default: exec)",
779+
help="Action: exec, eval, screenshot, startapp, freespace, backscreen, installapp, listapps, deleteapp (default: exec)",
780780
)
781781
parser.add_argument("args", nargs="*", help="Arguments")
782782
parser.add_argument("--binary", help="Path to lvgl_micropy_unix binary")
@@ -850,6 +850,46 @@ def main():
850850
out = ctrl.backscreen()
851851
sys.stdout.buffer.write(out)
852852
sys.stdout.buffer.write(b"\n")
853+
elif args.action == "installapp":
854+
if not args.args:
855+
print("error: app path required", file=sys.stderr)
856+
return 1
857+
apppath = args.args[0]
858+
import subprocess, os
859+
script_dir = os.path.dirname(os.path.abspath(__file__))
860+
mpremote = os.path.join(script_dir, "..",
861+
"lvgl_micropython/lib/micropython/tools/mpremote/mpremote.py")
862+
subprocess.run(["python3", mpremote, "mkdir", ":/apps"], capture_output=True)
863+
result = subprocess.run(
864+
["python3", mpremote, "fs", "cp", "-r", apppath, ":/apps/"],
865+
capture_output=True, timeout=60
866+
)
867+
if result.returncode != 0:
868+
print("error:", result.stderr.decode().strip(), file=sys.stderr)
869+
return 1
870+
print(f"Installed {os.path.basename(apppath)}")
871+
with ctrl:
872+
ctrl.exec("from mpos import AppManager ; AppManager.refresh_apps()")
873+
elif args.action == "listapps":
874+
with ctrl:
875+
out = ctrl.exec("""
876+
from mpos import AppManager
877+
for a in AppManager.get_app_list():
878+
print(a.fullname)
879+
""")
880+
sys.stdout.buffer.write(out)
881+
elif args.action == "deleteapp":
882+
if not args.args:
883+
print("error: app name required", file=sys.stderr)
884+
return 1
885+
appname = args.args[0]
886+
with ctrl:
887+
out = ctrl.exec(
888+
"from mpos import AppManager; "
889+
"AppManager.uninstall_app({!r})".format(appname)
890+
)
891+
sys.stdout.buffer.write(out)
892+
sys.stdout.buffer.write(b"\n")
853893
else:
854894
parser.print_help()
855895
return 1

tests/cpython_mpos_controller.py

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ def run_tests(mpos, only=None, is_serial=False):
6464
"interaction": test_interaction,
6565
"sessions": test_multiple_sessions,
6666
"navigation": test_app_navigation,
67+
"appmanagement": test_app_management,
6768
}
6869
if only:
6970
names = [s.strip() for s in only.split(",")]
@@ -244,10 +245,57 @@ def test_app_navigation(mpos, is_serial=False):
244245
check(isinstance(free, int) and free > 0, f"free space: {free} bytes")
245246

246247

248+
def test_app_management(mpos, is_serial=False):
249+
section("App management (install / list / remove)")
250+
if not is_serial:
251+
check(True, "skipped (desktop backend)")
252+
return
253+
254+
import subprocess, os
255+
256+
appname = "com.micropythonos.helloworld"
257+
apppath = os.path.abspath(
258+
os.path.join(os.path.dirname(__file__), "..",
259+
"internal_filesystem/apps", appname)
260+
)
261+
262+
script_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
263+
mpremote = os.path.join(script_dir,
264+
"lvgl_micropython/lib/micropython/tools/mpremote/mpremote.py")
265+
266+
subprocess.run(["python3", mpremote, "mkdir", ":/apps"], capture_output=True)
267+
result = subprocess.run(
268+
["python3", mpremote, "fs", "cp", "-r", apppath, ":/apps/"],
269+
capture_output=True, timeout=60
270+
)
271+
check(result.returncode == 0, f"installapp: cp exit code {result.returncode}")
272+
273+
mpos.exec("from mpos import AppManager ; AppManager.refresh_apps()")
274+
out = mpos.exec("""
275+
from mpos import AppManager
276+
for a in AppManager.get_app_list():
277+
print(a.fullname)
278+
""")
279+
check(appname.encode() in out, f"listapps shows {appname}")
280+
281+
out = mpos.exec(
282+
"from mpos import AppManager; "
283+
"AppManager.uninstall_app({!r})".format(appname)
284+
)
285+
check(b"Error" not in out, f"deleteapp succeeded: {out.decode().strip()}")
286+
287+
out = mpos.exec("""
288+
from mpos import AppManager
289+
for a in AppManager.get_app_list():
290+
print(a.fullname)
291+
""")
292+
check(appname.encode() not in out, f"listapps confirms {appname} removed")
293+
294+
247295
def main():
248296
parser = argparse.ArgumentParser(description="Test MPOSController backends")
249297
parser.add_argument("--serial", help="Serial port for device backend")
250-
parser.add_argument("--only", help="Comma-separated test sections: basic,ui,interaction,sessions,navigation")
298+
parser.add_argument("--only", help="Comma-separated test sections: basic,ui,interaction,sessions,navigation,appmanagement")
251299
parser.add_argument("--binary", help="Path to lvgl_micropy_unix binary")
252300
args = parser.parse_args()
253301

0 commit comments

Comments
 (0)