Vous avez identifié un bug dans l'un des paquets fournis par votre distribution favorite ? Ne vous résignez pas : vous pouvez le patcher !

Contexte

A la maison, notre PC familial tourne sous Windows 10. Pour la messagerie et l'agenda, plusieurs d'entre nous utilisent Outlook. Les calendriers sont hébergés dans une instance de Nextcloud. Pour les récupérer, Outlook passe par le plugin OutlookCaldav. Généralement cela fonctionne : les événements créés sur d'autres machines (le téléphone portable de l'un ou de l'autre) sont importés sans histoire.

A une exception près : les événements provenant de mon ordinateur portable génèrent systématiquement des erreurs : OutlookCaldav signale qu'ils sont mal formés et refuse de les importer. De fait, les fichiers .ics problématiques ne passent pas les tests de validation proposés par iCalendar.org. Clairement, ce n'est pas OutlookCaldav qui est déraille, mais mon ordinateur portable.

Ce portable a la particularité de tourner sous Manjaro, une distribution dérivée de Arch Linux. Mon gestionnaire de bureau est KDE, dont j'utilise l'agenda par défaut, Korganizer. Il s'avère que Korganizer, ou plutôt l'une de ses dépendances, Kcalcore, souffre d'un bug, signalé ici dès octobre 2017. Que faire ? attendre que les développeurs se réveillent ?

Heureusement, le fil de discussion du bug a déjà identifié le commit fautif -- une seule ligne, dans un seul fichier. Ce n'est donc pas trop compliqué de corriger ça à la main, en utilisant la documentation du Arch Build system et le tutoriel sur comment patcher les paquets Arch.

Prérequis

Sous Arch, la compilation s'automatise à l'aide de scripts nommés PKGBUILD. Pour récupérer des PKGBUILD depuis les dépôts, vous devez disposez d'un utilitaire nommé asp. Pour ma part, je n'ai pas pu installer asp via le gestionnaire de paquets pacman. Par contre, j'ai trouvé dans le AUR le paquet asp-https, qui fait très bien l'affaire.

Etape 1: récupérer le PKGBUILD

Créez et placez vous dans un répertoire vierge, par exemple ~/build.

mkdir ~/build && cd ~/build
asp export kcalcore

Ceci devrait télécharger le PKGBUILD de kcalcore. Vous obtenez donc l'arborescence suivante :

build
└── kcalcore
    ├── PKGBUILD

Etape 3 : récupérer les sources

cd ~/build/kcalcore
makepkg -o

L'option -o permet de télécharger les sources sans lancer leur compilation. makpkg va donc télécharger l'archive ~/build/kcalcore/kcalcore-18.12.1.tar.xz et l'extraire vers le répertoire ~/build/kcalcore/src/kcalcore-18.12.1/src/. Votre arborescence ressemble désormais à ceci :

build
└── kcalcore
    ├── kcalcore-18.12.1.tar.xz
    ├── kcalcore-18.12.1.tar.xz.sig
    ├── PKGBUILD
    └── src

Sur mon système, cette étape génère une erreur : kcalcore-18.12.1.tar.xz ... ÉCHEC (Clé publique inconnue DBD2CE893E2D1C87) ==> ERREUR : Une ou plusieurs signatures PGP n’ont pas pu être vérifiées. Là, je dois admettre que je ne suis pas entièrement au clair sur la démarche à suivre. J'ai choisi d'accepter la clé fournie en exécutant gpg --recv-keys DBD2CE893E2D1C87.

Etape 4 : modifier les sources et créer le patch

Il est maintenant temps de le corriger, ce fameux bug.

  1. Faites une copie des sources.

    cd kcalcore
    cp src/kcalcore-18.12.1/src/ src/kcalcore-18.12.1/src.new
  2. Modifiez à votre guise les sources copiées.

    Evidemment, cette étape dépend entièrement du paquet et du bug dont vous vous occupez. Dans mon cas, j'édite le fichier src/kcalcore-18.12.1/src.new/icaltimezones.cpp, dont je supprime la ligne 399, contenant l'instruction suivante :

    r.until = writeLocalICalDateTime(times.takeAt(times.size() - 1), preOffset);
  3. Vos modifications sauvegardées, vérifiez les différences entre la nouvelle et l'ancienne version avec diff -ura src/kcalcore-18.12.1/src src/kcalcore-18.12.1/src.new --color. Dans mon cas, j'obtiens ceci :

    diff -ura src/kcalcore-18.12.1/src/icaltimezones.cpp src/kcalcore-18.12.1/src.new/icaltimezones.cpp
    --- src/kcalcore-18.12.1/src/icaltimezones.cpp  2018-12-14 07:00:10.000000000 +0100
    +++ src/kcalcore-18.12.1/src.new/icaltimezones.cpp  2019-01-11 15:00:38.571659490 +0100
    @@ -396,7 +396,6 @@
                        } else if (rule & LAST_WEEKDAY_OF_MONTH) {
                            r.by_day[0] = -(dayOfWeek % 7 + 1) - (nthFromEnd * 8);       // Sunday = 1
                        }
    -                    r.until = writeLocalICalDateTime(times.takeAt(times.size() - 1), preOffset);
                        icalproperty *prop = icalproperty_new_rrule(r);
                        if (useNewRRULE) {
                            // This RRULE doesn't start from the phase start date, so set it into
    

    Cela semble conforme à mes souhaits, donc je crée le patch pour de bon : diff -ura src/kcalcore-18.12.1/src/icaltimezones.cpp src/kcalcore-18.12.1/src.new/icaltimezones.cpp > package.patch.

    Maintenant, dans ~/build/kcalcore, j'ai deux fichiers côte à côte : PKGBUILD et package.patch.

Etape 5 : intégrer le patch dans le PKGBUILD

  1. Ajoutez votre patch à la liste des sources.

    # PKGBUILD
    source=("https://download.kde.org/stable/applications/$pkgver/src/$pkgname-$pkgver.tar.xz"{,.sig}
    "package.patch")
  2. Du coup, vous devez recalculer les sommes de contrôle du le paquet, en exécutant dans la console la commande updpkgsums. Ceci va mettre à jour la ligne sha256sums du PKGBUILD.

  3. Indiquez au PKGBUILD qu'il devra importer le patch lors de l'étape prepare de la compilation.

    # PKGBUILD
    cd $srcdir/$pkgname-$pkgver
    patch -Np2 -i "${srcdir}/package.patch"
    cd -

    Ceci signifie qu'à l'exécution du script, on se déplacera vers le dossier ~/build/kcalcore/src/kcalcore-18.12.1, avant de lancer le patch, dont on omettra les 2 premiers niveaux (-p2) de l'arborescence. Si vous ouvrez notre package.diff, vous constaterez en effet qu'il se réfère à src/kcalcore-18.12.1/src/icaltimezones.cpp. Tronquons le début de ce chemin : on demande en fait de patcher le fichier src/icaltimezones.cpp depuis ~/build/kcalcore/src/src/kcalcore-18.12.1. Le chemin complet du fichier à patcher est donc bien ~/build/kcalcore/src/kcalcore-18.12.1/src/icaltimezones.cpp. Ce fichier existe, notre chemin est bon. Je suis d'accord, c'est un peu tortueux.

  4. Signalez dans le PKGBUILD que ce paquet a été modifié.

    # PKGBUILD
    groups=('modified')

Voilà, normalement, vous êtes tout bon.

Etape 6 : compiler

Dans le répertoire contenant le PKGBUILD, il ne reste plus qu'à exécuter makepkg (sans -o cette fois). Si tout se déroule sans heurt, vous verrez un joli message dans cette veine : Création terminée : kcalcore 18.12.1-1 (ven. 11 janv. 2019 15:29:58 CET). Un nouveau fichier aura fait son apparition à côté du PKGBUILD, portant un suffixe en pkg.tar.xz : c'est votre paquet tout frais, tout neuf !

Il se peut aussi que makepkg échoue pour cause de dépendances manquantes. Deux solutions s'offrent à vous :

  1. Exécutez à nouveau la commande, mais avec l'option --syncdeps. makepkg alors tentera d'installer automatiquement ce qui vous manque.

  2. Faites une recherche pour identifier par vous-même les ressources voulues, et installez-les avec pacman, avant de retenter la compilation.

    Ce n'est pas toujours évident de déterminer le nom du (des) paquet(s) voulus. Par exemple, dans mon cas, makepkg se plaignait de l'absence d'ECM. En réalité, il fallait installer un paquet nommé _extra_cmakemodules.

Etape 7 : installer

Fastoche : à ce stade, y'a plus qu'à faire makepkg -i (ou makepkg --install).

Et après ?

Pour éviter que pacman n'écrase le fruit de votre labeur à la prochaine misa à jour, ajouter cette ligne à /etc/pacman.conf.

IgnoreGroup = modified

Gardez précieusement votre PKGBUILD modifié et votre patch : quand une nouvelle version de votre paquet préféré sortira, vous devriez pouvoir la corriger en un tournemain.

Article suivant Article précédent