[FIX] script todo: ne plus empaqueter les dépôts du manifeste dans l'APK

La compilation butait sur « Too many zip entries 123678 (MAX=65535) » : un APK
est un ZIP, et le dépôt mobile verse 122 684 fichiers d'assets pour 337 qui
sont l'application. Le levier existe et il est documenté chez lui
(doc/SERVICES.md) : ERPLIBRE_MANIFEST_PATH, ici pointé sur un manifeste vide —
« ces dépôts-là : aucun ». Le plugin l'annonce, « 0 repos ».

Mesuré sur erplibre-ubuntu-2604-gnome : dist passe de 123 019 fichiers à 336,
l'APK sort à 59 Mo et 2 472 entrées, et la phase mobile entière rend 0, tests
Vitest compris — 75 fichiers, 1938 tests. Qui veut les dépôts pose la variable
lui-même : elle est respectée. Mesure d'attente, à retirer quand ils tiendront
sous le plafond du ZIP.

--- EN ---

The build hit "Too many zip entries 123678 (MAX=65535)": an APK is a ZIP, and
the mobile repo pours 122,684 asset files in for 337 that are the application.
The lever exists and that repo documents it (doc/SERVICES.md):
ERPLIBRE_MANIFEST_PATH, pointed here at an empty manifest — "those repos:
none". The plugin says so itself, "0 repos".

Measured on erplibre-ubuntu-2604-gnome: dist drops from 123,019 files to 336,
the APK comes out at 59 MB with 2,472 entries, and the whole mobile phase
returns 0, Vitest included — 75 files, 1938 tests. Set the variable yourself
and the repos come back. A stopgap, to drop once they fit under the ZIP
ceiling.

Assisted-by: Claude Opus 5
This commit is contained in:
Mathieu Benoit 2026-08-19 05:57:22 -04:00
parent 9e69cfa49c
commit aa94e460ec
6 changed files with 104 additions and 17 deletions

View file

@ -302,10 +302,17 @@ the dashboard, and the log names the probable cause instead of leaving a
40 MB Gradle log to read: disk full, missing SDK platform, JDK/Gradle 40 MB Gradle log to read: disk full, missing SDK platform, JDK/Gradle
mismatch, unaccepted licences, a Gradle daemon killed by the kernel (with the mismatch, unaccepted licences, a Gradle daemon killed by the kernel (with the
machine's RAM, swap and oom-kill count, because a memory cause is proven and machine's RAM, swap and oom-kill count, because a memory cause is proven and
not assumed), or too many asset files for one APK — a ZIP holds 65535 entries not assumed), or too many asset files for one APK. The heavy output goes to
and the mobile repo ships 122 684, which only that repo can fix. The heavy `~/erplibre-mobile-build.log` inside the VM so the install log stays readable.
output goes to `~/erplibre-mobile-build.log` inside the VM so the install log
stays readable. That last cause no longer stops the build. The mobile repo bundles the manifest
repositories into its assets — 122 684 files, for 337 that are the application
— and an APK is a ZIP, capped at 65535 entries: `Too many zip entries 123678`.
The build therefore points `ERPLIBRE_MANIFEST_PATH`, the lever that repo
documents, at an empty manifest, and the plugin says so: `0 repos`. Measured:
`dist` drops from 123 019 files to 336, and the APK comes out at 59 MB with
2 472 entries. Set the variable yourself and the repositories come back — the
default is a stopgap until they fit under the ZIP ceiling.
It is bounded to apt-based distributions, because that upstream installer It is bounded to apt-based distributions, because that upstream installer
starts with `sudo apt install openjdk-17-jdk`. It requires no Android Studio starts with `sudo apt install openjdk-17-jdk`. It requires no Android Studio
@ -439,10 +446,19 @@ NOMME la cause probable au lieu de laisser 40 Mo de journal Gradle à relire :
disque plein, plateforme SDK absente, JDK et Gradle incompatibles, licences non disque plein, plateforme SDK absente, JDK et Gradle incompatibles, licences non
acceptées, démon Gradle tué par le noyau (avec la RAM, le swap et le compte de acceptées, démon Gradle tué par le noyau (avec la RAM, le swap et le compte de
l'oom-killer, parce qu'une cause « mémoire » se prouve au lieu de s'affirmer), l'oom-killer, parce qu'une cause « mémoire » se prouve au lieu de s'affirmer),
ou trop de fichiers d'assets pour un APK — un ZIP tient 65535 entrées et le ou trop de fichiers d'assets pour un APK. Le détail va dans
dépôt mobile en embarque 122 684, ce que lui seul peut corriger. Le détail va `~/erplibre-mobile-build.log`, dans la VM, pour que le journal d'installation
dans `~/erplibre-mobile-build.log`, dans la VM, pour que le journal reste lisible.
d'installation reste lisible.
Cette dernière cause n'arrête plus la compilation. Le dépôt mobile empaquette
les dépôts du manifeste dans ses assets — 122 684 fichiers, pour 337 qui sont
l'application — et un APK est un ZIP, borné à 65535 entrées :
`Too many zip entries 123678`. La compilation pointe donc
`ERPLIBRE_MANIFEST_PATH`, le levier que ce dépôt documente, sur un manifeste
vide, et le plugin l'annonce : `0 repos`. Mesuré : `dist` passe de 123 019
fichiers à 336, et l'APK sort à 59 Mo et 2 472 entrées. Posez la variable
vous-même et les dépôts reviennent — le défaut est une mesure d'attente, le
temps qu'ils tiennent sous le plafond du ZIP.
Il est borné aux distributions apt, parce que cet installateur amont commence Il est borné aux distributions apt, parce que cet installateur amont commence
par `sudo apt install openjdk-17-jdk`. Il n'exige PAS Android Studio — une par `sudo apt install openjdk-17-jdk`. Il n'exige PAS Android Studio — une

View file

@ -191,10 +191,19 @@ NOMME la cause probable au lieu de laisser 40 Mo de journal Gradle à relire :
disque plein, plateforme SDK absente, JDK et Gradle incompatibles, licences non disque plein, plateforme SDK absente, JDK et Gradle incompatibles, licences non
acceptées, démon Gradle tué par le noyau (avec la RAM, le swap et le compte de acceptées, démon Gradle tué par le noyau (avec la RAM, le swap et le compte de
l'oom-killer, parce qu'une cause « mémoire » se prouve au lieu de s'affirmer), l'oom-killer, parce qu'une cause « mémoire » se prouve au lieu de s'affirmer),
ou trop de fichiers d'assets pour un APK — un ZIP tient 65535 entrées et le ou trop de fichiers d'assets pour un APK. Le détail va dans
dépôt mobile en embarque 122 684, ce que lui seul peut corriger. Le détail va `~/erplibre-mobile-build.log`, dans la VM, pour que le journal d'installation
dans `~/erplibre-mobile-build.log`, dans la VM, pour que le journal reste lisible.
d'installation reste lisible.
Cette dernière cause n'arrête plus la compilation. Le dépôt mobile empaquette
les dépôts du manifeste dans ses assets — 122 684 fichiers, pour 337 qui sont
l'application — et un APK est un ZIP, borné à 65535 entrées :
`Too many zip entries 123678`. La compilation pointe donc
`ERPLIBRE_MANIFEST_PATH`, le levier que ce dépôt documente, sur un manifeste
vide, et le plugin l'annonce : `0 repos`. Mesuré : `dist` passe de 123 019
fichiers à 336, et l'APK sort à 59 Mo et 2 472 entrées. Posez la variable
vous-même et les dépôts reviennent — le défaut est une mesure d'attente, le
temps qu'ils tiennent sous le plafond du ZIP.
Il est borné aux distributions apt, parce que cet installateur amont commence Il est borné aux distributions apt, parce que cet installateur amont commence
par `sudo apt install openjdk-17-jdk`. Il n'exige PAS Android Studio — une par `sudo apt install openjdk-17-jdk`. Il n'exige PAS Android Studio — une

View file

@ -176,10 +176,17 @@ the dashboard, and the log names the probable cause instead of leaving a
40 MB Gradle log to read: disk full, missing SDK platform, JDK/Gradle 40 MB Gradle log to read: disk full, missing SDK platform, JDK/Gradle
mismatch, unaccepted licences, a Gradle daemon killed by the kernel (with the mismatch, unaccepted licences, a Gradle daemon killed by the kernel (with the
machine's RAM, swap and oom-kill count, because a memory cause is proven and machine's RAM, swap and oom-kill count, because a memory cause is proven and
not assumed), or too many asset files for one APK — a ZIP holds 65535 entries not assumed), or too many asset files for one APK. The heavy output goes to
and the mobile repo ships 122 684, which only that repo can fix. The heavy `~/erplibre-mobile-build.log` inside the VM so the install log stays readable.
output goes to `~/erplibre-mobile-build.log` inside the VM so the install log
stays readable. That last cause no longer stops the build. The mobile repo bundles the manifest
repositories into its assets — 122 684 files, for 337 that are the application
— and an APK is a ZIP, capped at 65535 entries: `Too many zip entries 123678`.
The build therefore points `ERPLIBRE_MANIFEST_PATH`, the lever that repo
documents, at an empty manifest, and the plugin says so: `0 repos`. Measured:
`dist` drops from 123 019 files to 336, and the APK comes out at 59 MB with
2 472 entries. Set the variable yourself and the repositories come back — the
default is a stopgap until they fit under the ZIP ceiling.
It is bounded to apt-based distributions, because that upstream installer It is bounded to apt-based distributions, because that upstream installer
starts with `sudo apt install openjdk-17-jdk`. It requires no Android Studio starts with `sudo apt install openjdk-17-jdk`. It requires no Android Studio

View file

@ -6260,10 +6260,34 @@ class TODO:
"else sudo rm -f /swapfile-erplibre 2>/dev/null; " "else sudo rm -f /swapfile-erplibre 2>/dev/null; "
f'echo " {t("no swap could be added; build may run short")}"; ' f'echo " {t("no swap could be added; build may run short")}"; '
"fi; fi; " "fi; fi; "
f'echo " {t("manifest repos not bundled (ZIP entry limit)")}"; '
f'mstep "{t("npm dependencies")}" ' f'mstep "{t("npm dependencies")}" '
f"'cd {el_dir}/mobile/erplibre_home_mobile && npm ci' && " f"'cd {el_dir}/mobile/erplibre_home_mobile && npm ci' && "
# L'empaquetage des dépôts du manifeste est DÉSACTIVÉ, et c'est
# une mesure d'attente. Il verse 122 684 fichiers dans les assets —
# des dépôts Odoo entiers, pour 337 qui sont l'application — et un
# APK est un ZIP : « Too many zip entries 123678 (MAX=65535) », la
# compilation s'arrête là. Les mêmes fichiers épuisaient aussi les
# watches inotify de l'IDE.
#
# Le levier est celui que le dépôt mobile documente lui-même
# (doc/SERVICES.md) : ERPLIBRE_MANIFEST_PATH. On le pointe sur un
# manifeste VIDE — « ces dépôts-là : aucun » — et le plugin
# l'annonce, « 0 repos ». Mesuré : dist passe de 123 019 à 336
# fichiers, l'APK sort à 59 Mo et 2 472 entrées.
#
# Qui veut les dépôts pose la variable lui-même : elle est
# respectée. À retirer quand le projet mobile saura les empaqueter
# sous la limite du ZIP.
# Chaîné par « && » comme le reste : un « ; » ici laisserait la
# compilation web démarrer alors que « npm ci » vient d'échouer.
"printf '<manifest></manifest>' "
'> "$HOME/.erplibre-empty-manifest.xml" && '
f'mstep "{t("web bundle (vite build)")}" ' f'mstep "{t("web bundle (vite build)")}" '
f"'cd {el_dir}/mobile/erplibre_home_mobile && npm run build' && " f"'cd {el_dir}/mobile/erplibre_home_mobile && "
"ERPLIBRE_MANIFEST_PATH="
'"${ERPLIBRE_MANIFEST_PATH:-$HOME/.erplibre-empty-manifest.xml}" '
"npm run build' && "
f'mstep "{t("native sync (capacitor)")}" ' f'mstep "{t("native sync (capacitor)")}" '
f"'cd {el_dir}/mobile/erplibre_home_mobile && npx cap sync android' && " f"'cd {el_dir}/mobile/erplibre_home_mobile && npx cap sync android' && "
# UNE seule ABI, celle de la VM — qui est aussi celle de # UNE seule ABI, celle de la VM — qui est aussi celle de

View file

@ -2289,6 +2289,10 @@ TRANSLATIONS = {
"en": "no swap could be added; build may run short", "en": "no swap could be added; build may run short",
}, },
"memory:": {"fr": "mémoire :", "en": "memory:"}, "memory:": {"fr": "mémoire :", "en": "memory:"},
"manifest repos not bundled (ZIP entry limit)": {
"fr": "dépôts du manifeste non empaquetés (limite d'entrées ZIP)",
"en": "manifest repos not bundled (ZIP entry limit)",
},
"MB RAM,": {"fr": "Mo de RAM,", "en": "MB RAM,"}, "MB RAM,": {"fr": "Mo de RAM,", "en": "MB RAM,"},
"MB swap, kernel OOM kills:": { "MB swap, kernel OOM kills:": {
"fr": "Mo de swap, tués par le noyau (OOM) :", "fr": "Mo de swap, tués par le noyau (OOM) :",

View file

@ -340,6 +340,33 @@ class TestMobileBuild(unittest.TestCase):
res = self._run_steps(fail_on="gradle") res = self._run_steps(fail_on="gradle")
self.assertNotEqual(0, res.returncode, res.stdout[-400:]) self.assertNotEqual(0, res.returncode, res.stdout[-400:])
def test_a_failed_step_stops_the_ones_after_it(self):
"""La chaîne est en « && » d'un bout à l'autre. Un « ; » glissé au
milieu — celui qui écrivait le manifeste vide — laissait la compilation
web démarrer alors que « npm ci » venait d'échouer."""
res = self._run_steps(fail_on="npm")
self.assertNotEqual(0, res.returncode)
self.assertNotIn("vite build", res.stdout)
self.assertNotIn("gradle", res.stdout)
def test_the_manifest_repos_are_not_bundled(self):
"""122 684 fichiers d'assets pour 337 qui sont l'application, et un APK
est un ZIP borné à 65 535 entrées. Le levier est celui que le dépôt
mobile documente : ERPLIBRE_MANIFEST_PATH, pointé sur un manifeste
vide. Mesuré : dist passe de 123 019 à 336 fichiers."""
steps = self.todo._qemu_mobile_build_steps("/tmp/el")
self.assertIn("ERPLIBRE_MANIFEST_PATH=", steps)
self.assertIn("<manifest></manifest>", steps)
# La variable posée par l'appelant gagne : qui veut les dépôts les a.
self.assertIn("${ERPLIBRE_MANIFEST_PATH:-", steps)
def test_the_empty_manifest_is_written_before_the_bundle(self):
steps = self.todo._qemu_mobile_build_steps("/tmp/el")
self.assertLess(
steps.index("erplibre-empty-manifest.xml"),
steps.index("npm run build"),
)
def test_a_missing_apk_fails_even_when_gradle_returns_zero(self): def test_a_missing_apk_fails_even_when_gradle_returns_zero(self):
"""L'APK est la preuve, pas le code de sortie de Gradle : une tâche peut """L'APK est la preuve, pas le code de sortie de Gradle : une tâche peut
rendre 0 sans rien produire.""" rendre 0 sans rien produire."""