Bonjour,
je cherche via un script a connaitre la version d’un logiciel externe de type AppImage. Y-aurait-il un moyen pour le faire ?
Par exemple avec BalenaEtcher si je le lance je récupère un résultat (str) dans lequel il y a la version. J’ai essayé avec LibreOffice mais cela ne donne rien.
Une idée serait la bienvenue, …si c’est possible…
Selon AppStream metadata — AppImage documentation ça serait dans usr/share/metainfo/myapp.appdata.xml
.
Il doit exister un moyen de l’extraire, mais je l’ignore.
Par exemple avec binwalk on voit bien la structure de l’image :
$ binwalk python3.9.16-cp39-cp39-manylinux_2_24_x86_64.AppImage
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
7024 0x1B70 ESP Image (ESP32): segment count: 10, flash mode: QUIO, flash speed: 40MHz, flash size: 1MB, entry address: 0xc0012, hash: none
7408 0x1CF0 ESP Image (ESP32): segment count: 11, flash mode: QUIO, flash speed: 40MHz, flash size: 1MB, entry address: 0xc0012, hash: none
140480 0x224C0 SHA256 hash constants, little endian
140952 0x22698 xz compressed data
140992 0x226C0 CRC32 polynomial table, little endian
188392 0x2DFE8 Squashfs filesystem, little endian, version 4.0, compression:gzip, size: 20332416 bytes, 3017 inodes, blocksize: 131072 bytes, created: 1970-01-01 00:00:00
Après un petit binwalk -e
on trouve en effet le appdata.xml
:
$ cat _python3.9.16-cp39-cp39-manylinux_2_24_x86_64.AppImage.extracted/squashfs-root/usr/share/metainfo/python3.9.16.appdata.xml
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>python3.9.16</id>
<metadata_license>MIT</metadata_license>
<project_license>Python-2.0</project_license>
<name>Python 3.9</name>
<summary>A Python 3.9 runtime</summary>
<description>
<p> A relocated Python 3.9 installation running from an
AppImage.
</p>
</description>
<launchable type="desktop-id">python.desktop</launchable>
<url type="homepage">https://python.org</url>
<provides>
<binary>python3.9</binary>
</provides>
</component>
donc c’est possible, ma solution n’est pas élégante du tout, elle prouve que c’est possible.
Tu peux essayer ma manière avec ton appimage libreoffice pour voir à quoi ça ressemble.
Je parie qu’il existe des libs pour faire ça de manière un peu plus proprement.
Merci pour ta réponse, j’ai essayé mais cela ne donne rien d’intéressant avec binwalk et je n’ai pas de fichier particulier à LibreOffice dans usr/share/metainfo/myapp.appdata.xml
.
Ou as-tu récupéré l’appimage ? Si tu peux me donner le lien pour télécharger exactement la même je peux essayer.
voici l’adresse: LibreOffice as AppImage | LibreOffice - Free and private office suite - Based on OpenOffice - Compatible with Microsoft
Le fichier est Fresh full
Merci d’avance
En effet, j’y vois bien des “appdata” :
$ binwalk -e LibreOffice-fresh.full-x86_64.AppImage
$ find _LibreOffice-fresh.full-x86_64.AppImage.extracted -name '*.appdata.xml'
./libreoffice24.8-base.appdata.xml
./libreoffice24.8-calc.appdata.xml
./libreoffice24.8-draw.appdata.xml
./libreoffice24.8-impress.appdata.xml
./libreoffice24.8-writer.appdata.xml
./squashfs-root/usr/share/metainfo/libreoffice24.8-base.appdata.xml
./squashfs-root/usr/share/metainfo/libreoffice24.8-calc.appdata.xml
./squashfs-root/usr/share/metainfo/libreoffice24.8-draw.appdata.xml
./squashfs-root/usr/share/metainfo/libreoffice24.8-impress.appdata.xml
./squashfs-root/usr/share/metainfo/libreoffice24.8-writer.appdata.xml
Et … pas de version dans les fichiers appdata.xml
MAIS MAIS MAIS y’a la version dans le nom du fichier, libreoffice24.8-base.appdata.xml
hop, version 24.8
. C’est pas élégant (je trouve), c’est pas standard (j’ai pas lu le standard AppImage en entier), mais c’est là.
Je serai toi je leur demanderai poliment de rajouter ça dans le appdata.xml
pour la prochaine release
oui mais ce que voulais c’est la version complète, donc en l’occrence 24.8.2.1…Je n’avais compris comment récupérer l’ appdata.xml
.
Avec BalenaEtcher j’avais fait comme cela (surement pas catholique!):
#Cas BalenaEtcher (AppImage)
fb='b.AppImage'
result=subprocess.run('/home/bibi/Bureau/'+fb, capture_output=True, text=True)
if "'balenaEtcher@" in result.stdout:
i = result.stdout.find("'balenaEtcher@")
val=result.stdout[i:i+22].replace('@',' ').replace("'",'')
print(val)
Ohhh :
squashfs-root/startcenter.desktop:X-AppImage-Version=24.8.2.1.full
oui je viens aussi de le trouver et j’ai réussi à récupérer la version. Un grand merci pour ton aide
Ça doit s’automatiser un peu…
$ cat extract_version.py
import io
import os
from dissect.squashfs import SquashFS
with open("LibreOffice-fresh.full-x86_64.AppImage", mode="rb") as appimage:
while block := appimage.read(4):
if block == b'hsqs':
appimage.seek(-4, os.SEEK_CUR)
fsbytes = appimage.read()
fs = SquashFS(io.BytesIO(fsbytes))
with fs.get("/startcenter.desktop").open() as desktop_file:
desktop = desktop_file.read().decode("UTF-8")
for line in desktop.splitlines():
if line.startswith("X-AppImage-Version"):
print(line)
$ python extract_version.py
X-AppImage-Version=24.8.2.1.full
je vais regarder ton code, c’est surement plus élégant que le mien
J’ai essayé ton code qui fonctionne parfaitement, mais je n’ai pas le niveau technique pour le comprendre…
Ma version est beaucoup plus simpliste mais je suis obligé d’extraire tout puis de supprimer le-dit répertoire après avoir récupéré l’info de la version.
Bonjour @mdk, j’ai essayé d’analyser ta solution basée sur SquashFS. Vu mon niveau je ne sais pas si cela correspond bien à la réalité. Peux-tu me corriger svp:
ouvrir le fichier AppImage binaire
lire au moins 4 octets ? := affecte valeur et affiche
if block == b’hsqs’: si octets = ???
se positionner depuis la fin à partir du 4ème octet
lecture du fichier AppImage
pour créer une trame d’octets mémorisables
ouvrir le fichier .desktop qui nous intéresse
convertir en UTF-8 = transformer en str
éclater la trame
rechercher la ligne de version qui commence par
formater la sortie à afficher
afficher version de l’AppImage
ouvrir le fichier AppImage binaire
C’est juste. C’est le "rb"
qui donne l’indication : read
, binary
.
lire au moins 4 octets ? := affecte valeur et affiche
Oui pour le read
. Le :=
n’affiche pas, il affecte a block
, comme un =
. Mais contrairement à un =
, l’ensemble block := appimage.read(4)
vaut la valeur assignée, donc les 4 octets. Donc le while
va prendre en compte ces 4 octets pour savoir s’il faut, ou non, boucler. Si read
réussi à lire, le while
verra quelque chose qui n’est pas vide. “pas vide” en Python c’est vrai. Et à la toute fin, lorsque le read
échouera à lire (car le fichier est entièrement lu), while
verra quelque chose de vide, ce qui est faux en Python, et donc s’arrêtera.
J’aurai pu l’écrire :
block = appimage.read(4)
while block:
... tout le code du while
block = appimage.read(4)
mais ça oblige à écrire deux fois le appimage.read
, alors j’aime bien :=
.
if block == b’hsqs’: si octets = ???
Une chaîne de caractères préfixée par b
en Python c’est une séquence d’octets, donc là b'hsqs'
c’est les octets (qui correspondent aux caractères ASCII) h
, s
, q
, s
, soit les valeurs 104, 115, 113, 115. hsqs
c’est les 4 octets qui son toujours au début d’un squashfs, c’est dans la spec de squashfs. Y’a plein de format qui commencent par une suite d’octets « bien connue », ça permet de reconnaître un fichier, ça s’appelle souvent un « magic number ».
se positionner depuis la fin à partir du 4ème octet
Je dirais « reculer de 4 octets », mon but est de revenu au vrai début du squashfs, d’être pile sur le “h” du “hsqs”, car si block == "b’hsqs’ c’est que hsqs a déjà été lu, donc on est plus au début de l’appimage, il faut reculer de 4 octets pour se mettre au début de l’appimage.
lecture du fichier AppImage
pour créer une trame d’octets mémorisables
ouvrir le fichier .desktop qui nous intéresse
Oui, c’est un fichier texte.
convertir en UTF-8 = transformer en str
Exact, le texte est stocké sous forme d’octets (forcément), donc existe un algorithme pour transformer d’octet à texte et vice-versa, ce genre d’algo c’est un “encodage”, et UTF-8 est l’encodage qui marche bien de nos jours, il est top top top
éclater la trame
Je dirais : “découper le fichier en lignes”.
rechercher la ligne de version qui commence par
formater la sortie à afficher
Oh y’a pas vraiment de formattage ici c’est vraiment juste un print de la ligne SI elle commence par X-AppImage-Version.
merci infiniment pour ces explications, c’est vraiment agréable d’être épaulé ainsi, car je ne fais que bricoler (comme cela peut se supposer).
Je sais que j’abuse… J’ai effectivement trouvé quelque part que les premiers octets devaient être en hexa 68 73 71 73. Du coup j’ai essayé un xxd -l 0x10 lostd.AppImage
pour lire en hexa et en ASCII la première ligne du fichier AppImage, mais je trouve en hexa 7f 45 4c 46. Qu’est-ce que j’ai loupé ?..
Alors 68 73 71 73
, tu peux repérer les deux 73
, comme les deux s
dans hsqs
, c’est pas un hasard, c’est hsqs
:
$ printf hsqs | hexdump -C
00000000 68 73 71 73 |hsqs|
Mais c’est les premiers octets du SquashFS pas de l’AppImage. L’AppImage contient des données AVANT le SquashFS.
Dans mon code, rajoute :
print(appimage.tell(0))
juste après le :
appimage.seek(-4, os.SEEK_CUR)
ça te dira à quel octet se situe le début du SquashFS dans l’AppImage.
Mais attention le SquashFS ne commence pas au même octet dans toutes les AppImage. Il doit exister un moyen élégant de trouver le début du SquashFS dans l’AppImage, en lisant bien la spec de AppImage, moi dans mon code j’ai fait ça a la rache en cherchant octet par octet le ‘hsqs’, c’est moche, c’est fragile, mais c’est vite codé
Vu - par contre tell
ne prend pas d’argument : appimage.tell()
Ta solution est efficace et rapide
Exact, tell
ne prend pas d’argument, hey tu progresse vite !