Skip to content

Commit ff78cba

Browse files
committed
[PHAROS] Fix typos and harden launchscript for updates
1 parent d4200c3 commit ff78cba

4 files changed

Lines changed: 112 additions & 27 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
version = "1.0.4"
1+
version = "1.0.5"

buildtools/pharos/app/pharos.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -644,8 +644,7 @@ def _render_service(self) -> None:
644644
"",
645645
"It runs at boot, fires a notification if any installed",
646646
"ports are out of date, and re-checks whenever you exit a",
647-
"game. Notifications appear as an EmulationStation toast",
648-
"or a MuOS overlay message.",
647+
"game. Notifications appear as an EmulationStation toast.",
649648
]
650649
for i, line in enumerate(description):
651650
y = 50 + i * 22
@@ -754,7 +753,7 @@ def _handle_self_update_input(self) -> None:
754753
self.self_update_prompted = True
755754
if self.updater.download():
756755
self.ui.draw_log(
757-
text=f"Pharos v{self.updater.latest_version} downloaded — restart to apply.",
756+
text=f"Pharos v{self.updater.latest_version} downloaded — applying and re-launching...",
758757
background=True,
759758
)
760759
self.ui.render_to_screen()

buildtools/pharos/app/update.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@
88
from PHAROS_REPO@main, and looks up the download URL from docs/ports.json.
99
2. download() streams the new zip into DATA_DIR/.pending_update.zip with a
1010
progress UI driven by Pharos's existing draw_loader/draw_log primitives.
11-
3. main.py::apply_pending_update() picks up the zip on next launch and
12-
extracts it over the install dir before any other imports.
11+
3. The Pharos App.sh wrapper picks up the zip — both pre-launch (if a
12+
prior run left one) and post-exit (if Pharos just downloaded one and
13+
set running=False). It extracts via 7zzs into a temp dir, copies the
14+
pharos/ contents to GAMEDIR and the launcher script to its actual
15+
runtime location, then exec's itself to relaunch the new binary.
16+
See ports/released/apps/pharos/Pharos App.sh::apply_pending_update.
1317
"""
1418
import json
1519
import os

ports/released/apps/pharos/Pharos App.sh

Lines changed: 103 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,49 +18,131 @@ get_controls
1818

1919
# Variables
2020
GAMEDIR="/${directory}/ports/pharos"
21+
GAMEPARENT="${GAMEDIR%/*}"
22+
PENDING_ZIP="${GAMEDIR}/.pending_update.zip"
2123
LOG_DIR="${GAMEDIR}/logs"
24+
RUN_LOG="${LOG_DIR}/$(date +'%Y-%m-%d').log"
25+
26+
# Find the launcher path
27+
SCRIPT_PATH="$(readlink -f "$0" 2>/dev/null)"
28+
[ -z "${SCRIPT_PATH}" ] && SCRIPT_PATH="$0"
29+
SCRIPT_DIR="$(dirname "${SCRIPT_PATH}")"
30+
SCRIPT_NAME="$(basename "${SCRIPT_PATH}")"
2231

2332
cd "${GAMEDIR}" || exit 1
2433

34+
mkdir -p "${LOG_DIR}"
35+
2536
# Exports
2637
export XDG_DATA_HOME="${GAMEDIR}"
27-
export LOG_FILE="${LOG_DIR}/$(date +'%Y-%m-%d').log"
38+
export LOG_FILE="${RUN_LOG}"
2839
export SDL_GAMECONTROLLERCONFIG="${sdl_controllerconfig}"
2940
export PYSDL2_DLL_PATH="/usr/lib"
3041
export LD_LIBRARY_PATH="${GAMEDIR}/libs:${LD_LIBRARY_PATH}"
3142
export controlfolder
3243
export DEVICE_ARCH
3344

34-
mkdir -p "${LOG_DIR}"
45+
notify() {
46+
if command -v pm_message >/dev/null 2>&1; then
47+
pm_message "$1"
48+
fi
49+
echo "[Pharos.sh] $(date '+%H:%M:%S') $1" >> "${RUN_LOG}"
50+
}
3551

36-
# Apply any pending self-update
3752
apply_pending_update() {
38-
local zip="${GAMEDIR}/.pending_update.zip"
39-
local parent
40-
parent="$(dirname "${GAMEDIR}")"
41-
{
42-
echo "[Update] Applying pending update from ${zip}..."
43-
if "$controlfolder/7zzs.${DEVICE_ARCH}" x -y "${zip}" -o"${parent}" >/dev/null; then
44-
rm -f "${zip}"
45-
chmod +x "/{directory}/ports/Pharos App.sh"
46-
echo "[Update] Applied; re-launching."
47-
export _PHAROS_UPDATE_APPLIED=1
48-
exec "$0" "$@"
53+
seven_zip="${controlfolder}/7zzs.${DEVICE_ARCH}"
54+
tmpdir=""
55+
56+
if [ ! -x "${seven_zip}" ]; then
57+
notify "Update apply: 7zzs not found at ${seven_zip}."
58+
rm -f "${PENDING_ZIP}"
59+
return 1
60+
fi
61+
62+
if ! "${seven_zip}" t "${PENDING_ZIP}" >>"${RUN_LOG}" 2>&1; then
63+
notify "Update apply: pending zip is corrupt; deleted."
64+
rm -f "${PENDING_ZIP}"
65+
return 1
66+
fi
67+
68+
tmpdir="$(mktemp -d 2>/dev/null)"
69+
[ -z "${tmpdir}" ] && tmpdir="${LOG_DIR}/.update_tmp.$$"
70+
mkdir -p "${tmpdir}" 2>/dev/null
71+
72+
notify "Applying Pharos update..."
73+
if ! "${seven_zip}" x -y "${PENDING_ZIP}" -o"${tmpdir}" >>"${RUN_LOG}" 2>&1; then
74+
notify "Update apply: extraction failed; see ${RUN_LOG}."
75+
rm -rf "${tmpdir}"
76+
rm -f "${PENDING_ZIP}"
77+
return 1
78+
fi
79+
80+
# --- Data dir ---
81+
if [ ! -d "${tmpdir}/pharos" ]; then
82+
notify "Update apply: zip is missing pharos/ directory; aborting."
83+
rm -rf "${tmpdir}"
84+
rm -f "${PENDING_ZIP}"
85+
return 1
86+
fi
87+
if ! cp -rf "${tmpdir}/pharos/." "${GAMEDIR}/" >>"${RUN_LOG}" 2>&1; then
88+
notify "Update apply: data copy failed; see ${RUN_LOG}."
89+
rm -rf "${tmpdir}"
90+
rm -f "${PENDING_ZIP}"
91+
return 1
92+
fi
93+
94+
# --- Launcher ---
95+
launcher_in_zip="$(ls "${tmpdir}"/*.sh 2>/dev/null | head -n1)"
96+
launcher_name="${SCRIPT_NAME}"
97+
if [ -n "${launcher_in_zip}" ] && [ -f "${launcher_in_zip}" ]; then
98+
launcher_name="$(basename "${launcher_in_zip}")"
99+
# Stage to a sibling .new then rename — atomic on the same FS,
100+
# so the in-flight `exec` below never sees a half-written script.
101+
if cp -f "${launcher_in_zip}" "${SCRIPT_DIR}/${launcher_name}.new" >>"${RUN_LOG}" 2>&1 \
102+
&& chmod +x "${SCRIPT_DIR}/${launcher_name}.new" >>"${RUN_LOG}" 2>&1 \
103+
&& mv -f "${SCRIPT_DIR}/${launcher_name}.new" "${SCRIPT_DIR}/${launcher_name}" >>"${RUN_LOG}" 2>&1; then
104+
:
49105
else
50-
echo "[Update] Extraction failed; deleting partial zip."
51-
rm -f "${zip}"
106+
notify "Update apply: launcher swap failed at ${SCRIPT_DIR}; old launcher kept."
107+
rm -f "${SCRIPT_DIR}/${launcher_name}.new"
108+
launcher_name="${SCRIPT_NAME}"
109+
fi
110+
# If the launcher was renamed across versions, drop the old one.
111+
if [ "${launcher_name}" != "${SCRIPT_NAME}" ] && [ -f "${SCRIPT_DIR}/${SCRIPT_NAME}" ]; then
112+
rm -f "${SCRIPT_DIR}/${SCRIPT_NAME}"
113+
fi
114+
# Mirror into ${GAMEPARENT} too if that's a separate location
115+
# and a launcher already exists there.
116+
if [ "${SCRIPT_DIR}" != "${GAMEPARENT}" ] && [ -f "${GAMEPARENT}/${launcher_name}" ]; then
117+
cp -f "${SCRIPT_DIR}/${launcher_name}" "${GAMEPARENT}/${launcher_name}" >>"${RUN_LOG}" 2>&1
118+
chmod +x "${GAMEPARENT}/${launcher_name}" >>"${RUN_LOG}" 2>&1
52119
fi
53-
} >> "${LOG_FILE}" 2>&1
120+
fi
121+
122+
rm -rf "${tmpdir}"
123+
rm -f "${PENDING_ZIP}"
124+
chmod +x "${GAMEDIR}/Pharos" 2>>"${RUN_LOG}"
125+
export _PHAROS_UPDATE_APPLIED=1
126+
exec "${SCRIPT_DIR}/${launcher_name}" "$@"
54127
}
55128

56-
if [ -f "${GAMEDIR}/.pending_update.zip" ] && [ -z "${_PHAROS_UPDATE_APPLIED}" ]; then
129+
# Pre-launch apply: catches the path where the user came back to the menu
130+
# and re-launched manually after a previous download.
131+
if [ -f "${PENDING_ZIP}" ] && [ -z "${_PHAROS_UPDATE_APPLIED}" ]; then
57132
apply_pending_update "$@"
58133
fi
59134

60-
# Permissions
135+
# Defensive +x on the binary.
61136
chmod +x "${GAMEDIR}/Pharos"
62137

63-
pm_platform_helper "${GAMEDIR}/Pharos" >/dev/null
64-
"${GAMEDIR}/Pharos" "${GAMEDIR}/.sources" > "${LOG_FILE}" 2>&1 || true
138+
# Run
139+
pm_platform_helper "${GAMEDIR}/Pharos" >>"${RUN_LOG}" 2>&1
140+
"${GAMEDIR}/Pharos" "${GAMEDIR}/.sources" >>"${RUN_LOG}" 2>&1
141+
142+
# Post-exit apply
143+
if [ -f "${PENDING_ZIP}" ]; then
144+
apply_pending_update "$@"
145+
fi
65146

147+
# Cleanup
66148
pm_finish

0 commit comments

Comments
 (0)