From d7851763f7799118c09b7b7e46841b87114c9993 Mon Sep 17 00:00:00 2001 From: smueller Date: Thu, 28 May 2026 17:24:05 +0200 Subject: [PATCH] refactor(obfuscate_release): improve source file selection and cleanup logic, enhancing error handling for asset processing --- .../obfuscate_release.cpython-314.pyc | Bin 18493 -> 20166 bytes scripts/obfuscate_release.py | 54 ++++++++++++++++-- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/scripts/__pycache__/obfuscate_release.cpython-314.pyc b/scripts/__pycache__/obfuscate_release.cpython-314.pyc index 0051a92739143bdd083ea1115c0245e875b476db..6ee1bb96aa678be90ed286afb375b8b48581ac15 100644 GIT binary patch delta 4042 zcma)9YfxLq72eewy$}zHha_}`c*!7P-WVGKm`4&447ZL*Q`v+_7f_6aypo)RW(-c# zDR$i&cbkMbX-hK6gk;(VkCL(bNQ>P}GVPB}oH$02nKo_mul)hBnRq;XoxMWHc>JR~ zqi^?~-LsFg=X`tg-W>kmCs<#p*QpT{#lif?-Hm7T`S`Un<$hdw?vxt0@D+K8cjlo9 zL!|hCgWu8oFhYJkLKbwO#EuRW+fhB!g;I}`^*H7w4&pQxlu?y)V>Sa{%oest%y>P0x^6hOPB zRusTac|ZM|l}`T!MuoKiGw7Y1rNQ%_bDnq1!~g;(CI_IpC67i%UCnRegh~kdCjEin zm{UpMdJzFrAmRZ?WDsG*KO7OBj3ku%zR^v{BuQjH6b!(4p-W&W%E&$#>{O9QnWC3L z!y^pYYzcX2Vk8huC?|E zKcSzCUQt|}iphDICYrVVHxx+gSZG?&R9?|k#&awmYc1Fs z&M+plxoc9WZ-v3l(8Z?g&JxL`lB~{M@=MJakk%A8(3yHecG5s2Fesr2PezGPpvP=A z!avz*?c!;_Mj5zpoxuV`1ymPgVzrzr3dIZbNnmKIfD<4H2Ymf2Xs{pwuN(relnmKf ztd8Z0jxQO&bp4(j%C#$Ls6nOQ^l(@coL2%-VWj3NE&XL-iM$uQUP2$;ol9q2s%abQ z`)1PLd8z1)ved#}MXDt_BYZJuq4|z^v2nR3sF_lYwv~Ode;# zLkuPuFegeVqQQwk@Q_m`+G?5**3-p6bQZQe^A!RdgcA9_31K7{4Gjl^M@J?C{^4-o zG0+|hlP92CG^+rO8FbBHoR!5jnWx$oa^En&Vt&K=s`WFtHMsYJxT)}k;F;j!*j(@v zQ{!we+`XZE;fa;Z>MNNY)p4!ibl-`-A3k_J3uT#Z-cWD5dQi?k*~>1!;8r*bmU=zA zgOgn3aylC27aK6(=G|w}QCqQugy~#m3BDOyvOR|J6wR?uRXzn;WC|c53z11*7%r2Y zFnK^Fi3W##hyCQcAiYU1*#D?uLkXj~B*|RQpI+b_DFfZT4&(kh*`BAOjyL*nzjzga}HpFyUpfxq*OhU)XL(dg({{5&kaZKFSFmd z0=NH;6&@H6U#4x_D7kac775tXBtZXBR=i`XgsUJzI5J5DPH>O8x$?0B|-M1{NNKy^bWx;5hxFq5|Se z>+Dwl6a-?7d`TCoO?x!O3(YHNOFO5h{6Z?F#{IT~o&M ziwv3poQfpViWGB}Nnc{{G7VLi$zOryeX*CS7cfq;*cctDd8=gWRQ*nAatAJ^!xjTU z7i*uT)wLD!*P%H^y|r)S!!d2063c%9g2Obw{?*O-j>JB%cS{t>3F*$dTw2jIhy^;; zx9_m&Sa{x5xNPhqR*e+SvZzh=Oa8NyDQ&=6r_Boa6(41?P<$0bJ@{06|O zC(Eq8L}jgZx%lK!SL=TDpFk+?%t*iAI;e_kvQD}eAVulH!+HOORGEAwX4V{S_`uT4{r4IRV|*Q4SM=|2!& z2OaJ(%E1cWQr2>QCz)t?3sSls=|JjfNr|B5v#7N*Pp9=lx|}Q?Exp!Zb7bHCiu~W2 z9i2wJgAR4tdzs^k#Uo8oV@T(%PDzJc>66@Mket+5I5{Nj&RqKY&U*X@dZW{aKcWxs z-8py(W|%T}^ZY)(1^xkXVyeO=^FMBMl5kUQH^*<%;V79r%m}bbB*qr*Zp27W?QOvM z^wQpzAaiyW0pZDsqk>3&kZ+SfFp`jlp9+&_pqq%^$Rg%8mwcanvLuNxek3fo$q)k; zrU}jXNO*jBBpenXOJiP0Sj0H>^wF+Dyv)3`RrJz?6r4IC4ULDyfD5zNp4(QEX^iYJ z`~x6gK(FYl@6na6cc*vkTr!=voU_D=uI^~RtS!5&wat3w>sF1W3&K*}C&s4Po_MD5 zFX+%GZX2k^!oDc-rE a#kg%lrNetRIH0ACb_`*@_6W7!%l!`%D{~D1 delta 2628 zcma)8X>41^5#HtFA@P(f%9cc3lqibSK~slq$&stm5*;0uUmdz>DANr29MNJZb{~~E zY7r|z4>^}D4}!{t1F(gW$jy(~Weq!LQ=oNv{g9C+bqO^AiU9486p+vgK??-!&Z9}m zMt*dG_wDS=?#%AY?CiVs3VruHH8-10dcs@9RN1Mk-X(JxU0!O8Q1`VL^wcv|C%U@6 zK}f_*NF|x7x05Nmopj=S-a2WvpQfU!p17ORt8}N0&coj-Yg9}F7QLhEBR)fRaabT< z5H)SvKv;fo9lMpV(%lr4?tQf)V?}&&Sbzg1gBLeQuFVvHO0LJRFLcSS+skj9GTMcLa%n8}ZVS!v8T%m7huV^oiDt6qIO>w?k z#rPRXMtD3LcdOY6PO|{QH<7DJ#6r=ytmd@S>8xek6(m!Xh=yl^^6VT7OTm-Tn8cL z8oaA&FFeyd3Vn_`xM**rYw5F&M=70w&l~2o=m<6gF=wsjNlvc8lJmEQ8Dye2SPWg= z@^?#~-$tG0p~ z&~jx;n=F89ZC0-+nH>vghNm25EP(`BDUGpE!T=HaV z*A<#6kmBLlNHqQ!eAZl-_O>uuRh%hgQYaEkN~e?TFyCHA?+?Z1q=SsjGI+1Gvjj7n zVJXUJrPEP4DKi;V9v8m?&7On$m$^X6@ZZ3^r@my>_Q1`dn|oKw2R<|pt`-b_rZc7g z;Q0}C{L(YHci2I0ISj+?!mZt^5evE1Mv-n8IQ@a8V#E#4dHd*7cxh-;dflrM4BtlE z-$8g9zU;7-p5f%YDIAkR@z$^`w}xX;_6)RkR-gDDmrS@#><2jcEW&dL8ieN&UO;#e zA%7sY7l-E%&LebjaBJBR(#kDfLh1qn!0Vk(%`zvO(jRxGC{^w@^}(gRKXv4HIl;@D zvVm4ygT^>RQMUxA_PI2dIL8M+-1i2ZNRM>ssOBe{xr!n6~ZrsI*yyaJWaJ z5xCytrjNjg3R#X83U7I zp=9(4DVUsPKICZU;<0FahNbzyZDw!c)YqV6z+RBiW{WyJJaAP1YtC1;WP%$5N1$l% z=UO{y+_Ub2-wm?v1>7ta8QiR$nl=y?!%CNZ#<(os@E-AZivDw6fbVxX(iey3C=GyR zc${{?)NrGvKs0YXwSgMgJyNQ15fZQ?<=#U`A*m*Td=c>rll6J!c|x?nKSp+$41tCm z%Wr_!M{4Sewin(1du6e&lsci&XCHCr_2nOdgfY;Z;~s0-R(SIjNi5D4x*Bqv@K<>U zobz?kci>mPF#SEa4tdpYa}99i&>p%IK0UPm3}z9gmOLAKLSh(E{{FIPJed*Xr(~Ao zjBJQ86}QD1%LBt}!;T@~1;`ktL-KSmB+C-7B^XME`Q|odw22UtC6-Z#*kdx*rNnHI z&CVv-o836;2*Sf0GP)q2DaDgpe*^3U3V(q@Au*j$5?(g(A^hdRa{VWqP_iO=Vf1=^ zbK6ztjh1UIY0t;a{kM&cw~e)n$Cd}zN*hwr)s7EK_bm=X%UGGtKw1XqzsxW?mTq@s z^ugfCx#S#^fF+xdT0++ydqB zSvPzF?~ixrKj#vj!9;!wz8wEn8~-8OG#AoG=w=!IJZuiBY;=rn_6XFwX{7XPn*}D? Tvsue8;${!e^K~D*I#K&SN?tw1 diff --git a/scripts/obfuscate_release.py b/scripts/obfuscate_release.py index 0c4df20..95c222c 100644 --- a/scripts/obfuscate_release.py +++ b/scripts/obfuscate_release.py @@ -210,11 +210,39 @@ def collect_asset_groups(asset_root: Path) -> dict[tuple[Path, str, str], list[P return groups -def pick_source_file(paths: list[Path], base: str, ext: str) -> Path: - plain = paths[0].parent / f"{base}{ext}" +def pick_source_file(paths: list[Path], base: str, ext: str) -> Path | None: + if not paths: + return None + + parent = paths[0].parent + plain = parent / f"{base}{ext}" + ordered: list[Path] = [] if plain in paths: - return plain - return min(paths, key=lambda p: len(p.name)) + ordered.append(plain) + for candidate in sorted(paths, key=lambda p: len(p.name)): + if candidate not in ordered: + ordered.append(candidate) + + for candidate in ordered: + try: + content = candidate.read_text(encoding="utf-8") + except (OSError, UnicodeDecodeError): + continue + if is_valid_source_content(content): + return candidate + return None + + +def cleanup_invalid_siblings(paths: list[Path], source: Path) -> None: + for path in paths: + if path == source or not path.exists(): + continue + try: + content = path.read_text(encoding="utf-8") + except (OSError, UnicodeDecodeError): + content = "" + if not is_valid_source_content(content): + path.unlink() def run_cmd(command: list[str], cwd: Path) -> None: @@ -232,7 +260,10 @@ def run_cmd(command: list[str], cwd: Path) -> None: def process_js(path: Path, cwd: Path) -> None: original = path.read_text(encoding="utf-8") if not is_valid_source_content(original): - raise ValueError(f"invalid or corrupted JS source: {path}") + raise ValueError( + f"invalid or corrupted JS source: {path} " + f"(restore e.g. 'git checkout dev -- {path.as_posix()}')" + ) if shutil.which("npx"): tmpdir = Path(tempfile.mkdtemp()) @@ -360,6 +391,8 @@ def build_hash_mapping(public_root: Path) -> dict[str, str]: groups = collect_asset_groups(asset_root) for (parent, base, ext), paths in groups.items(): source = pick_source_file(paths, base, ext) + if source is None: + continue digest = hash_file(source) target = parent / f"{base}.{digest}{ext}" rel_new = target.relative_to(public_root).as_posix() @@ -397,8 +430,17 @@ def main() -> int: asset_root = public_root / "assets" if asset_root.exists(): groups = collect_asset_groups(asset_root) - for (_parent, base, ext), paths in sorted(groups.items()): + for (parent, base, ext), paths in sorted(groups.items()): source = pick_source_file(paths, base, ext) + if source is None: + rel = (parent / f"{base}{ext}").relative_to(public_root) + print( + f"ERROR: No valid source for {rel}. " + f"Restore from dev, e.g.: git checkout dev -- {rel}", + file=sys.stderr, + ) + return 1 + cleanup_invalid_siblings(paths, source) if ext == ".js": process_js(source, repo_root) else: