• Facile
Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Introduction du cours

Se nourrir de tutos faits maison c’est bien, mais il faut aussi que les zéros découvrent le monde extérieur, l’hors-SdZ. Il y a sur le net de très bonnes ressources sur la plupart des sujets, et il est toujours intéressant de lire directement ce que les gens concernés ont à dire.

Dans cette optique, je vous propose ici de lire Richard Jones, un développeur chez Red Hat (une des entreprises basées uniquement sur le logiciel libre qui a le plus de succès dans le monde). Richard Jones a la chance d’être payé pour contribuer chaque jour au logiciel libre, et à force il en connaît un rayon. Il vous expliquera ici quelles sont les bonnes pratiques à respecter quand on veut intégrer son travail (sous forme de code source) dans un logiciel libre. Écrire le code ne fait pas tout, il faut savoir présenter son travail aux responsables du projet, afin qu’ils l’acceptent et que votre code soit enfin proposé à la foule d’utilisateurs en liesse.

Ce sont des conseils de bon sens, mais que l’on a vite fait d’oublier dans le feu de l’action. J’en ai moi-même fait l’expérience, alors que je contribuais du code précisément à l’un des projets dont Richard Jones est l’auteur ! À l’époque cet article n’existait pas encore, mais il m’aurait bien servi. Il a aussi été apprécié par certains zéros participant au Google Summer of Code en 2009 (manifestation dont on a déjà parlé sur le SDZ, qui est basée sur le fait de contribuer du code à des logiciels libres existants, et qui demande un bon niveau technique), comme Cygal (projet pour BZFlag) ou rz0 (xmltools, pour NetBSD).

Remarque : Richard Jones vient d’un milieu assez technique, donc les exemples logiciels qu’ils emploient sont d’un bon niveau. En particulier le conseil d’aller lire les modifications du noyau Linux n’est peut-être pas adapté sur le Site du Zéro. J’ai choisi de rester au plus près du document, mais vous pouvez prendre de la distance.

J’ai parfois inséré des précisions dans le texte, elles sont signalées par un petit "ndt" (note du traducteur).

Ouverture

Une des choses que j’ai remarquées, depuis que je travaille chez Red Hat, c’est que même des programmeurs expérimentés, s’ils n’ont pas l’habitude des "trucs open source", peuvent ne pas comprendre du tout pourquoi leurs contributions à des projets libres sont souvent ignorées, rejetées ou critiquées.

Dans cet article, je vais vous dire ce que vous pouvez faire pour qu’un projet libre accepte votre contribution, et comment éviter les erreurs les plus courantes.

Quelques termes importants pour la suite :

  • upstream
    C’est le terme passe-partout pour désigner l’origine du projet; le groupe de contributeurs principaux, leurs mailing-lists, leur site web, etc. Par exemple, beaucoup de compagnies distribuent le serveur web Apache, mais il n’y a qu’un seul upstream (en amont, ndt.), c’est sur apache.org.

  • contributeur
    C’est vous, ainsi que tous les autres gens qui envoient des modifications, des corrections de bugs, des nettoyages de code et autres améliorations à l’upstream.

Communiquez dès le début

L’upstream déteste ça. Ce sont souvent des volontaires avec un temps disponible limité, le code est toujours difficile à comprendre, surtout quand il en arrive une grande quantité tout d’un coup. Si vous partez dès que vous avez "fait" votre contribution, c’est encore plus difficile pour eux parce qu’ils n’ont personne pour demander de l’aide et des explications.

Vous verrez souvent des gens faire référence à ce principe sous le nom de "Publiez tôt, publiez souvent" (Release Early, Release Often), et il vient d’un chapitre du célèbre essai d’Eric Raymond, La Cathédrale et le Bazar. Raymond parlait alors de quelque chose de légèrement différent : les releases (ndt. sortie de la première version, ou d’une nouvelle version du logiciel) précoces et fréquentes du noyau Linux. Votre contribution n’est sans doute pas tout à fait aussi importante, mais c’est quand même du code, et ça profite aussi de discussions dès le début, régulièrement, de la publication de code aussi tôt que possible, des commentaires de l’upstream, et des tests des utilisateurs.

Envoyez des patches, pas des paquets de code

Les développeurs upstream, comme on l’a déjà dit, n’ont pas beaucoup de temps. Ils veulent avoir juste ce qui a changé. Il y a un format spécial utilisé par les développeurs pour montrer juste les parties qui ont changé, qui s’appelle un patch.

Les patches aident les développeurs upstream, en leur montrant directement ce que vous avez modifié. Les outils de développement sont aussi conçus pour comprendre les patches, ce qui les rend particulièrement faciles à utiliser.

Si vous envoyez juste un paquet de code, vous obligez le développeur upstream à en faire un patch lui-même pour voir ce qui a changé. C’est désagréable pour eux, et en pratique beaucoup ne feront pas l’effort, ou n’auront pas le temps de regarder.

Voici un bon exemple d’un patch très simple soumis à un projet libre. Remarquez qu’il y a un sujet très clair, et une explication de ce que fait le patch, et qu’ensuite le patch lui-même montre juste ce qui a changé.

  • De: Chris Lalancette <clalance redhat com>

  • À: libvir-list redhat com

  • Sujet: libvirt PATCH : Nettoyage simplissime de commentaires dans src/domain_conf.c

  • Date: Vendredi 25 Juillet 2008 18:16:12 +0200

Le sujet dit à peu près tout, à part le détail mineur qu’est l’utilisation de "domain.xml" dans xmlReadDoc(). Vraiment, ce nettoyage rend juste le code plus facile à lire.

Index: src/domain_conf.c
===================================================================
RCS file: /data/cvs/libvirt/src/domain_conf.c,v
retrieving revision 1.8
diff -u -r1.8 domain_conf.c
--- a/src/domain_conf.c        25 Jul 2008 14:27:25 -0000        1.8
+++ b/src/domain_conf.c        25 Jul 2008 16:14:05 -0000
@@ -1396,7 +1396,7 @@
     }
     def->id = -1;
 
-    /* Demander quel genre de virtualisation QEMU utiliser */
+    /* Demander quel genre de virtualisation utiliser */
     if (!(tmp = virXPathString(conn, "string(./@type)", ctxt))) {
         virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
                              "%s", _("missing domain type attribute"));
@@ -1762,7 +1762,7 @@
     }
     VIR_FREE(nodes);
 
-    /* analyse des périphériques d'entrée */
+    /* analyse des périphériques d'affichage */
     if ((n = virXPathNodeSet(conn, "./devices/graphics", ctxt, &nodes)) < 0) {
         virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
                              "%s", _("cannot extract graphics devices"));
@@ -1847,7 +1847,7 @@
     xmlNodePtr root;
     virDomainDefPtr def = NULL;
 
-    if (!(xml = xmlReadDoc(BAD_CAST xmlStr, "network.xml", NULL,
+    if (!(xml = xmlReadDoc(BAD_CAST xmlStr, "domain.xml", NULL,
                            XML_PARSE_NOENT | XML_PARSE_NONET |
                            XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
         virDomainReportError(conn, VIR_ERR_XML_ERROR, NULL);

Ndt. Afin qu’il soit compréhensible, j’ai traduit ce patch en français; attention à ne pas le confondre avec le mail envoyé par l’auteur cité.

Découpez vos patches

Déjà, un gros patch c’est presque aussi mauvais qu’un gros tas de code : il est difficile pour des développeurs surchargés et sous-payés de le garder en tête et de le comprendre en une fois. Ensuite, faire des modifications indépendantes dans un seul patch c’est mal, car peut-être que certaines modifications seulement peuvent être acceptées et que les autres demandent encore du travail.

Contrairement à mes autres conseils, découper les patches demande un peu de talent. Peut-être que la meilleure façon de le comprendre est d’étudier quelques beaux exemples dans le domaine, et rien ne vaut la mailing-list du noyau Linux, où certains des plus brillants et des meilleurs programmeurs découpent des patches conceptuellement compliqués en une série de patches simples. Voici un exemple :

  • patch en 13 parties pour KVM (fonctionnalité de virtualisation native de Linux) par Avi Kivity et al.

C’est important pour deux raisons. Premièrement, les programmeurs utilisent une technique nommée bisection pour identifier celui des patches d’une série qui a provoqué l’apparition d’un bug donné. Si des patches individuels dans une série cassent quelque chose, alors ils empêchent aussi la bisection. Deuxièmement, ça facilite le travail à l’upstream s’il veut appliquer certains de vos patches, mais pas tous, ce qui est en général mieux que les forcer à tout rejeter en bloc.

Patchez par rapport à la version de développement la plus récente

Les développeurs upstream utilisent la version de développement, et ils vont certainement avoir besoin d’appliquer vos patches sur cette version ou de les donner à leur système de gestion de versions. Si ça ne marche pas proprement, ça leur fait beaucoup plus de boulot, et souvenez-vous qu’ils sont sans doute des bénévoles qui sont vraiment à court de temps libre.

Les versions de développement peuvent parfois être assez différentes de la dernière version stable publiée, surtout sur les projets au développement rapide. Alors assurez-vous que vous suivez toujours la dernière version, et publiez vos patches à partir celle-ci.

Une autre chose à préciser ici, c’est que parfois vous allez vous retrouver avec des patches qui n’ont pas encore été acceptés par l’upstream. Peut-être qu’ils ont juste besoin de plus de travail et d’utilisation. C’est important de les garder synchronisés avec la version de développement, et si cela s’avère nécessaire vous devriez publier de temps en temps une nouvelle version à jour de votre patch, et l’envoyez à la mailing-listupstream (on appelle ce procédé un rebasing du patch).

Lancez les tests s’il y en a

Encore une fois, les tests sont importants et difficiles à bien faire. Ce n’est pas sympa de refiler cette tâche aux développeurs upstream. Vous devez vous assurer que votre patch marche comme vous le présentez, et qu’il ne casse aucun code existant.

Mettez à jour la documentation et les tests

Si vous ajoutez juste la fonctionnalité au code, cela revient à demander à l’upstream de mettre à jour la documentation, les pages de manuel, les pages web pour y décrire votre fonctionnalité. L’upstream pourrait même avoir besoin de rajouter des tests automatisés pour garantir que votre fonctionnalité continuera à marcher dans le futur.

Souvenez-vous que les développeurs upstream sont souvent des volontaires, et que dans tous les cas écrire la documentation est un travail difficile.

Aidez les développeurs upstream, en créant une fonctionnalité complète. Cela inclut toute la documentation nécessaire pour que les utilisateurs en prennent connaissance. Cela inclut tous les tests automatiques pour s’assurer que des changements futurs ne vont pas casser cette fonctionnalité.

Questions légales

Si vous contribuez pendant votre temps de travail (ou simplement, sous certaines juridictions, si vous êtes employé), vous pourriez avoir besoin de l’autorisation de votre employeur avant de contribuer des fonctionnalités significatives à des projets libres (ndt. appartenant au domaine de votre travail).

Certains projets ont besoin d’un champ Signed-Off-By (authentifié par) ajouté au patch, ou d’une manière quelconque d’attribuer la source d’un patch à une personne en particulier. Faites l’effort de regarder si le site web upstream ou les fichiers sources contiennent des recommandations sur comment soumettre des patches, et suivez leurs conseils.

Patches tombés dans l'oubli

Si personne n’a commenté votre patch, ou s’il a été accepté mais pas effectivement intégré upstream, alors, après un délai convenable, vous devriez revenir sur le sujet.

Si personne n’a commenté votre patch la première fois, il faut reformuler vos explications, et s’assurer qu’il respecte toutes les règles citées ici.

Accepter un éventuel refus

C’est un fait : certaines modifications ne sont pas acceptées par l’upstream. Il peut y avoir de nombreuses raisons à cela, mais dans les projets bien gérés c’est en général parce qu’ils ne correspondent pas bien aux buts globaux du projet. Peut-être qu’un éditeur d’images n’est pas la bonne fonctionnalité pour cet éditeur de documents petit et rapide. Parfois cela arrive pour des raisons moins honorables, mais quelle qu’en soit la raison, vous ne pouvez pas obliger les développeurs upstream à accepter votre patch.

Néanmoins, le logiciel libre vous donne de nombreuses libertés, et si vous pensez vraiment que votre patch est ce qu’il faut pour le projet, vous avez en gros deux possibilités :

  1. maintenir ce qu’on appelle des patches out of tree (externes au projet)

  2. forker le projet

Patches externes au projet

Un patch out of tree est un patch que vous hébergez, et que vous continuez à mettre à jour, mais qui ne fait pas officiellement partie du projet upstream.

Les patches out of tree sont très courants dans certains projets (en particulier le noyau Linux qui en a probablement des milliers). Cependant, vous devez bien vous rendre compte que cela implique beaucoup de travail. À chaque fois que l’upstream publie une nouvelle version, il y a un risque que cela casse votre patch, vous obligeant à le remettre à jour (ce qui peut être beaucoup de travail). De plus, vous aurez peut-être besoin de proposer à vos utilisateurs différentes versions du patch, correspondant aux différentes versions upstream. C’est pourquoi c’est une bonne idée de travailler avec l’upstream pour y intégrer vos patches le plus possible. Même découper votre patch pour en faire accepter certaines parties par l'upstream vaut généralement le coup.

Fork d'un projet

C’est la bombe atomique en matière de logiciel libre : annoncer que vous allez forker le projet. Cela signifie que vous allez créer votre propre projet dérivé, et donc devenir votre propre upstream. Vous pouvez alors, évidemment, ajouter tous les patches que vous voulez dans votre version.

Forker un projet peut être une bonne idée, en particulier quand l’upstream actuel est inactif, ne répond pas, se sont eux-même rendus particulièrement mal appréciés des autres contributeurs (comme le projet XFree86). Mais commencez par regarder s’il y a d’autres développeurs intéressés par la création d’un nouveau projet : il vaut mieux se mettre ensemble plutôt que diviser la main d’oeuvre entre différents projets identiques.

Si vous forkez un projet, soyez bien préparé. En particulier, n’utilisez pas le même nom ou un nom proche, qui pourrait provoquer des confusions ou même des problèmes légaux. Soyez préparé à investir une grande quantité de travail, au moins autant d’efforts que l’upstream originel (souvenez-vous de cette règle si vous envisagez de forker un projet qui a des centaines de contributeurs). Énoncez des buts clairs et précis, qui soient différents de ceux de l’upstream originel. Et si possible, forkez amicalement — peut-être que l’upstream sera content que vous dirigiez le projet dans une autre direction.

Eric Raymond explique les dynamiques du fork de projets en terme de réputation des développeurs, qu’il appelle la noosphère, dans cet essai.

Trucs pratiques et ressources externes

Créer des patches

Pour créer un patch à partir d’un seul fichier, il faut penser, avant de faire la moindre modification au fichier, à en faire une copie de sauvegarde (backup) :

cp fichier.c fichier.c.orig

Ensuite vous pouvez modifier le fichier, tester vos changements, etc. Quand vous êtes satisfaits du résultat, créez un patch comme ceci :

diff -u fichier.c.orig fichier.c > ma-super-fonctionnalite.patch

Notes :

  • Utilisez toujours le format de diff unifié, -u. N’oubliez pas l’option -u en ligne de commande.

  • Faites toujours dans l’ordre diff -u vieux_fichier   nouveau_fichier, sinon vous obtiendrez ce qu’on appelle un "patch inversé".

Pour créer un patch de plusieurs fichiers à la fois (par exemple sur l’ensemble d’une version d’un logiciel), décompressez ses sources en deux endroits différents :

tar zxf projet-1.0.tag.tz
mv projet-1.0 projet-1.0.orig
tar zxf projet-1.0.tag.tz

Cela devrait créer deux répertoires comme ceci :

Citation

$ ls projet-1.0.orig/ projet-1.0/

Faites vos modifications dans le second répertoire (celui qui n’est pas .orig). Ensuite, pour créer un patch, revenez au répertoire parent et faites :

diff -ur projet-1.0.orig projet-1.0 > super-truc.patch

Lisez la page de manuel de la commande diff pour plus d’informations.

Systèmes de gestion de versions

La plupart du temps, vous utiliserez en fait un système de gestion de versions tel que CVS, Subversion, git, Mercurial, etc. Ces temps-ci, il y en a beaucoup. Ils ont pour la plupart des commandes pour générer des patches automatiquement — vous récupérez le code, faites les modifications que vous voulez, et lancez la commande pour que le logiciel fasse le patch pour vous. La table ci-dessous donne quelques commandes courantes et des liens vers la documentation plus avancée :

CVS

cvs diff - u

Manuel

Subversion

svn diff

Page d'accueil

Git

git format-patch

Manuel

Mercurial

hg diff

Page d'accueil

Bazaar (bzr)

bzr send

Manuel, Page d'accueil

Outils pour gérer des ensembles de patches
Le principal outil pour gérer des ensembles de patches est nommé quilt. Il y a une bonne présentation de quilt ici (en).

Git a des branches légères (une branche est une série de patches), git-rebase --interactive ..permet de réordonner/modifier/réunir/séparer des groupes de modifications, il y a aussi git stash et d’autres choses encore.

Licences logicielles

Les trois licences les plus courantes que vous rencontrerez sont :

Pour une liste plus complète, vous pouvez aller voir la page Wikipédia de comparaison des licences libres.

Autres documents décrivant la soumission de patches

Les Directives du noyau Linux sont assez semblables à cet article, et sont un must-read si vous voulez soumettre votre code au noyau.

Le fichier HACKING des coreutils décrit comment formater et envoyer des patches au projet GNU coreutils. Ça explique très en détail comment utiliser git pour soumettre des patches. (Merci à Jim Meyering).

Article original (non traduit) : How to get your code into an open source project.

Écrit par Richard Jones. Avec les commentaires de Daniel Berrange, Daniel Veillard, Jim Meyering et Cristophe Troestler.

Traduit par bluestorm, avec la motivation et les commentaires de Cygal.

Note : Contrairement à mes habitudes, ce tutoriel est sous licence "copie non autorisée". En effet, je ne suis pas l'auteur de l'article original, ce n'est donc pas à moi de choisir le mode de diffusion de celui-ci. Si un jour son auteur précise une licence plus permissive pour son texte, je la reproduirai ici.

Exemple de certificat de réussite
Exemple de certificat de réussite