From 9ccac0a4d5872bae2bc64c7ebf684895ed18d791 Mon Sep 17 00:00:00 2001 From: mawei Date: Fri, 9 Oct 2026 22:32:30 +0800 Subject: [PATCH] updater: bundle the pyserial-free zipapp (commaai/openpilot#38925); drop the pyserial bootstrap --- launch_chffrplus.sh | 34 ------------------------ openpilot/common/hardware/comma/updater | Bin 24709205 -> 24709209 bytes 2 files changed, 34 deletions(-) diff --git a/launch_chffrplus.sh b/launch_chffrplus.sh index 88bfedf9f..f30e03ca6 100755 --- a/launch_chffrplus.sh +++ b/launch_chffrplus.sh @@ -80,40 +80,6 @@ function launch { ln -sfn teleoprtc_repo/teleoprtc teleoprtc ln -sfn tinygrad_repo/tinygrad tinygrad - # The bundled AGNOS updater zipapp imports pyserial (tici/lpa.py inside the - # archive). agnos_init may invoke that updater, so make sure serial is - # importable first. Offline wheel in third_party/wheels is tried before the - # PyPI fallback. Installs into $DIR/pydeps without touching the device venv. - if [ -f /AGNOS ]; then - # Put pydeps on PYTHONPATH unconditionally BEFORE the import test and the - # AGNOS updater run. Previously the export was gated on an import test that - # ran without pydeps on PYTHONPATH, so it never fired even when the wheel - # install succeeded, and the updater still crashed on `import serial`. - PYDEPS="${PYDEPS:-$DIR/pydeps}" - mkdir -p "$PYDEPS" - case ":$PYTHONPATH:" in - *":$PYDEPS:"*) ;; - *) export PYTHONPATH="$PYDEPS:$PYTHONPATH" ;; - esac - if ! python3 -c "import serial" > /dev/null 2>&1; then - echo "[bootstrap] pyserial missing before AGNOS check; installing..." - wheel_dir="$DIR/third_party/wheels" - if [ -d "$wheel_dir" ] && ls "$wheel_dir"/pyserial*.whl > /dev/null 2>&1; then - echo "[bootstrap] pyserial: installing from local wheel..." - python3 -m pip install --no-index --no-deps --find-links "$wheel_dir" --target "$PYDEPS" --upgrade pyserial > /tmp/pip_pyserial.log 2>&1 - fi - if ! python3 -c "import serial" > /dev/null 2>&1; then - echo "[bootstrap] pyserial: installing from PyPI (needs network)..." - python3 -m pip install --target "$PYDEPS" --upgrade pyserial > /tmp/pip_pyserial.log 2>&1 - fi - if python3 -c "import serial" > /dev/null 2>&1; then - echo "[bootstrap] pyserial: ok" - else - echo "[bootstrap] pyserial NOT available; AGNOS updater may fail importing serial" - fi - fi - fi - # hardware specific init if [ -f /AGNOS ]; then agnos_init diff --git a/openpilot/common/hardware/comma/updater b/openpilot/common/hardware/comma/updater index e7093649c8dc1775a74d17888a097d1ad2001cd8..784fc432c96aa9d4e5b29ffde77b4e82eb6c98a2 100755 GIT binary patch delta 13627 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 C6;pr! delta 13774 zcmZvC30PHC_r7~yoDoq}1o47HibrJ<0Z|kboF@e50dU9xO~46F6LM!}$DuDZt4|g- z_^Fkmk(rrbmSvjZkY-w9IaONPV1v`|UHhJ+_x}6yJgjxzcdfnlJe_;atiD+LOZ*oo zp`>ysFI81lQ`J=sRa4bcwUxK3qkL3d<*Vwc`pQo=Pz_Zh<*yp602Qd3s36r;IaRO< zQO#6y)k3vYkEm9vwF*^jl%d+HcB;J!Q{gH?MXD&(K}D;MDn`YsIMqqTtIn#6N>E)@ zHTrbTWXuyu1eGnwNt&VO4U1R zmwH$2R`01j>V36WeW3QKGF7hjs}I!y^^y8m9aNvFPt_synL4bFsL$0=^@XZX$JB9k zLY-7!s#EH;`bwQqU#qj~occz6tIn%RbwPcnzE>C3C3RU{QCHOu>PPjHx~8tHpVcqw zhPtVKRllj<)gS7X`cwU-{#O5}+v<+GtL~}$%Y-R}DTV0}rk60Q3bUFps|&M+Fl!34 zmN07z(_5Hzgy|#9y2A7oW<6on7p9*u8wj(ZFdGTeUzm-B86eC+VKxzFkT9DH(<#hg zVTK5^nJ}9RvxP8Q3iA?O?J!t5i= zzQXJ$%>Ke0Ak2Zn93;%a!b}x=hlqC%*R1*5nq4~wR;jYHto-m0(OQzPfWzzmVbBAvxh7Q7EN|KXvXlILq#Nl^zKz&3D9eqkO;bR|qIZj-`-mcn^v@Um zBp}1Zmm2ky-t%ZjK)z@~z2>EfI#g0MUxdnmHu(%lyWIDX&MBX>O-Ep=N$+^&3tyVQ zz_T)w7g#}`X`C;j<;5iy3|47qfQukQMGGoHzCpxX4T{8bq?oF?=Ctn0JXmTk=H@D| zi{=uWv}L&XS?iY6E)ao5EM-AYkYiTq44P3zX_}}?*R*jSHEWVDM$1*DZpON_4WuD= zUUnm^76oyi^%k@vI3IJO8>&`=hG_Cka}V-0ka1G9vdEhZg_Clda#eal8e*tMsp18# zoirQ0-iZE$%_+XNJfocXB1(QAr^7TMXQy=3^jVPT?L>>bUepETIZcipXOS&Xz-ZZd zp#|qIOc(X&DUgOpq7vwSVv*L(sA&i)B|fsyoUijmV=}=xrS}@0JcNz_c9KCw8aAN8 zMd=vTL%BF8<+gM*)_X98%J1AwHRvA5_VUmd zR`SH=oLp46!J3p%k^W$WZGnSRrg%DB0vRJueq*JIXpt|vN}rn^K}?Vx9pzDIdOS6u z^N`UF=S&+fZkdmY#X=g6F&=Ce$0iS4jn2a>UREwHYR!>i9^t0-r!44HF;Z*0OTW0q zW54#HdBR8hS6hN8r&YeFPHi9!bT+4QaS5_zAxFdzg)Iz&^gi@Jk*sw~dV0-J%)W?r z`RMYd6&&}2L1=ri(y|{x+8A-hLP2ZUJ35qeX+Rm!<7EH0DH9KE=|{*&x%Qw1D-RAu zi3YWSul(sVE<+0{0_rS3KTZV(7wHZgk?~@nmNekRP*GbKC6IE!_=q9eGD5tpb#pog zkGfQ|Er;~J$srq2KcEOX^){mhwBhzp42l=o!;5@}3EB@4K$Rduy-wPMKh>!>%&K;% zR|7n2KYtp4M|;_EEtjj%GJ#%0AG)l>qaWSJ{PU)qka<{9uV|OU{)loNB7mIjxmuOf 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