<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr" xml:base="https://vincent.bernat.ch">
  <title>Vincent Bernat — Distribution &gt; Debian</title>
  <link href="https://vincent.bernat.ch/fr/blog/atom-distribution-debian.xml" rel="self"/>
  <link href="https://vincent.bernat.ch/fr/blog#tag-distribution-debian" rel="alternate"/>
  <id>http://www.luffy.cx/fr/blog/atom-distribution-debian.xml/</id>
  <updated>2026-09-08T05:27:44Z</updated>

  <entry>
    <title type="html">Rétrogradage des paquets Debian à une date précise</title>
    <author><name>Vincent Bernat</name></author>
    <link href="https://vincent.bernat.ch/fr/blog/2020-downgrade-debian" rel="alternate"/>
    <link href="https://vincent.bernat.ch/fr/blog/2020-downgrade-debian#isso-thread" rel="replies" type="text/html"/>
    <updated>2020-01-30T20:58:39Z</updated>
    <id>http://www.luffy.cx/fr/blog/2020-downgrade-debian.html</id>

    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p>Contrairement à <a href="https://nixos.org/" title="Linux distribution with a unique approach to package and configuration management">NixOS</a>, Debian ne dispose pas d’un mécanisme
intégré permettant de remonter le temps à un moment précis. Cependant,
grâce à <a href="http://snapshot.debian.org/">snapshot.debian.org</a>, une archive des paquets Debian, il
est possible de rétrograder tous les paquets vers les versions
présentes à une date choisie.</p>
<p>Supposons que nous voulions retrouver l’état au 20 janvier 2020. Dans
<code>/etc/apt/sources.list.d/snapshot.list</code>, nous ajoutons une source
correspondant à cette date :</p>
<div class="language-debian-sourcelist codehilite"><pre><span/><code><span class="k">deb</span><span class="w"> </span><span class="sx">[check-valid-until=no]</span><span class="w"> </span><span class="kp">https://snapshot.debian.org/archive/debian/20200120T111800Z/</span><span class="w"> </span><span class="kp">unstable</span><span class="w"> </span><span class="kp">main</span><span class="w"> </span><span class="kp">contrib</span><span class="w"> </span><span class="kp">non-free</span>
</code></pre></div>

<p>Dans <code>/etc/apt/preferences.d/snapshot.pref</code>, nous définissons la
priorité de tous les paquets issus de cette source à 1001. C’est
au-dessus de la priorité par défaut de 500 et au-dessus de 1000 pour
autoriser à revenir à une version plus ancienne. La <a href="https://manpages.debian.org/apt_preferences.5.html#How_APT_Interprets_Priorities" title="Page de manuel pour apt_preferences(5)">page de manuel de
<code>apt_preferences(5)</code></a> contient les explications associées.</p>
<div class="language-debian-control-file codehilite"><pre><span/><code><span class="k">Package</span><span class="p">:</span><span class="w"> </span><span class="s">*</span>
<span class="k">Pin</span><span class="p">:</span><span class="w"> </span><span class="s">origin snapshot.debian.org</span>
<span class="k">Pin-Priority</span><span class="p">:</span><span class="w"> </span><span class="s">1001</span>
</code></pre></div>

<p>Après avoir exécuté <code>apt update</code>, nous pouvons vérifier le résultat avec <code>apt policy</code>:</p>
<div class="language-bash-session codehilite"><pre><span/><code><span class="gp">$ </span>apt<span class="w"> </span>policy
<span class="go">Package files:</span>
<span class="go"> 100 /var/lib/dpkg/status</span>
<span class="go">     release a=now</span>
<span class="go">1001 https://snapshot.debian.org/archive/debian/20200120T111800Z unstable/non-free amd64 Packages</span>
<span class="go">     release o=Debian,a=unstable,n=sid,l=Debian,c=non-free,b=amd64</span>
<span class="go">     origin snapshot.debian.org</span>
<span class="go">1001 https://snapshot.debian.org/archive/debian/20200120T111800Z unstable/contrib amd64 Packages</span>
<span class="go">     release o=Debian,a=unstable,n=sid,l=Debian,c=contrib,b=amd64</span>
<span class="go">     origin snapshot.debian.org</span>
<span class="go">1001 https://snapshot.debian.org/archive/debian/20200120T111800Z unstable/main amd64 Packages</span>
<span class="go">     release o=Debian,a=unstable,n=sid,l=Debian,c=main,b=amd64</span>
<span class="go">     origin snapshot.debian.org</span>
<span class="go">[…]</span>
</code></pre></div>

<p>En demandant une <em>mise à jour</em>, on se voit proposer de revenir sur les
versions présentes à l’instant choisi :</p>
<div class="language-bash-session codehilite"><pre><span/><code><span class="gp">$ </span>sudo<span class="w"> </span>apt<span class="w"> </span>upgrade
<span class="go">Reading package lists... Done</span>
<span class="go">Building dependency tree</span>
<span class="go">Reading state information... Done</span>
<span class="go">Calculating upgrade... Done</span>
<span class="go">The following NEW packages will be installed:</span>
<span class="go">  libdns-export1104 libgspell-1-1 libiptc0 libisc-export1100</span>
<span class="hll"><span class="go">The following packages will be DOWNGRADED:</span>
</span><span class="go">  bash-completion bear binutils binutils-common binutils-dev binutils-doc</span>
<span class="go">  binutils-x86-64-linux-gnu bison blackbird-gtk-theme blender blender-data</span>
<span class="go">  clang-6.0 clang-7 clang-8 clang-tools-8 cpp-9 cppcheck cpuid cups</span>
<span class="go">  […]</span>
<span class="go">0 upgraded, 4 newly installed, 451 downgraded, 0 to remove and 0 not upgraded.</span>
<span class="go">Need to get 1,053 MB/1,060 MB of archives.</span>
<span class="go">After this operation, 9,282 kB disk space will be freed.</span>
<span class="go">Do you want to continue? [Y/n]</span>
</code></pre></div>
      </div>
    </content>
  </entry>
  <entry>
    <title type="html">Petit traité empirique de l'empaquetage Debian</title>
    <author><name>Vincent Bernat</name></author>
    <link href="https://vincent.bernat.ch/fr/blog/2019-empaquetage-debian-empirique" rel="alternate"/>
    <link href="https://vincent.bernat.ch/fr/blog/2019-empaquetage-debian-empirique#isso-thread" rel="replies" type="text/html"/>
    <updated>2019-05-27T18:12:54Z</updated>
    <id>http://www.luffy.cx/fr/blog/2019-empaquetage-debian-empirique.html</id>

    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<div class="admonition">
<p class="admonition-title">Note</p>
<p>Ce guide est une mise à jour d’une <a href="/fr/blog/2016-empaquetage-debian-empirique">version
précédente</a>. Si vous
avez besoin de construire des paquets pour des distributions plus anciennes
que Debian Stretch et Ubuntu Bionic, jetez un œil sur l’édition précédente.</p>
</div>
<p>Bien que la création de paquets Debian soit <a href="https://www.debian.org/doc/manuals/maint-guide/index.fr.html" title="Guide des nouveaux responsables Debian">abondamment</a>
<a href="https://www.debian.org/doc/manuals/maint-guide/index.fr.html" title="Guide des nouveaux responsables Debian">documentée</a>, la plupart des <a href="https://www.debian.org/doc/manuals/packaging-tutorial/packaging-tutorial" title="Lucas Nussbaum's packaging tutorial">tutoriaux</a> ciblent
les paquets respectueux de la <a href="https://www.debian.org/doc/debian-policy/" title="La charte Debian">charte Debian</a>. De plus, leur
création a longtemps eu la <strong>réputation d’être particulièrement
difficile</strong><sup id="fnref:difficulty"><a class="footnote-ref" href="#fn:difficulty">1</a></sup> et beaucoup se sont tournés vers des outils
moins contraignants<sup id="fnref:fpm"><a class="footnote-ref" href="#fn:fpm">2</a></sup> tels que <a href="https://github.com/jordansissel/fpm" title="Effing package management">fpm</a> ou <a href="https://web.archive.org/web/2016/http://checkinstall.izto.org/" title="CheckInstall">CheckInstall</a>.</p>
<p>Toutefois, la construction de paquets Debian en utilisant les outils
officiels est plutôt simple en appliquant ces quelques concessions :</p>
<ol>
<li>
<p><strong>Aucun paquet source ne sera généré</strong>. Les paquets seront
    construits directement depuis une copie propre issue du système de
    versions.</p>
</li>
<li>
<p><strong>Des dépendances supplémentaires peuvent être téléchargées
    pendant la construction</strong>. Empaqueter individuellement chaque
    dépendance est un travail ingrat, notamment avec certains
    environnements tels que Java, JavaScript et Go.</p>
</li>
<li>
<p>Les paquets produits peuvent <strong>combiner et inclure des dépendances
    tierces</strong>. Cela peut lever certaines objections liées à la
    sécurité et à la maintenance à long terme, mais c’est une
    concession courante dans certains écosystèmes tels que Java,
    JavaScript et Go.</p>
</li>
</ol>
<div class="toc">
<ul>
<li><a href="#ceinture-blanche">Ceinture blanche</a><ul>
<li><a href="#le-fichier-de-controle">Le fichier de contrôle</a></li>
<li><a href="#la-recette">La recette</a></li>
</ul>
</li>
<li><a href="#ceinture-jaune">Ceinture jaune</a><ul>
<li><a href="#les-dependances-sources">Les dépendances sources</a></li>
<li><a href="#les-dependances-binaires">Les dépendances binaires</a></li>
<li><a href="#integration-avec-un-systeme-de-demarrage">Intégration avec un système de démarrage</a></li>
</ul>
</li>
<li><a href="#ceinture-verte">Ceinture verte</a><ul>
<li><a href="#banalites">Banalités</a></li>
<li><a href="#construction-automatique">Construction automatique</a></li>
<li><a href="#fichiers-supplementaires">Fichiers supplémentaires</a></li>
</ul>
</li>
<li><a href="#autres-exemples">Autres exemples</a></li>
</ul>
</div>
<h1 id="ceinture-blanche">Ceinture blanche</h1>
<p>Deux types de paquets coexistent dans l’archive Debian : les <strong>paquets
sources</strong> et les <strong>paquets binaires</strong>. Un paquet source produit un ou
plusieurs paquets binaires. Chaque paquet doit porter un nom.</p>
<p>Comme indiqué lors de l’introduction, aucun paquet source ne sera
construit. Nous allons travailler directement sur sa représentation
décompressée : une arborescence de fichiers incluant le répertoire
<code>debian/</code>. Les exemples qui suivent utilisent une arborescence
composée uniquement du répertoire <code>debian/</code>, mais ce dernier peut être
inclus dans n’importe quel projet existant.</p>
<p>Comme point de départ, nous allons empaqueter <a href="https://memcached.org/" title="memcached - a distributed memory object caching system">memcached</a>, un cache
mémoire distribué. Il nous faut créer quatre fichiers :</p>
<ul>
<li><code>debian/compat</code> ;</li>
<li><code>debian/changelog</code> ;</li>
<li><code>debian/control</code> ;</li>
<li><code>debian/rules</code>.</li>
</ul>
<p>Le premier contient uniquement <code>11</code><sup id="fnref:compat"><a class="footnote-ref" href="#fn:compat">3</a></sup> :</p>
<div class="language-bash codehilite"><pre><span/><code><span class="nb">echo</span><span class="w"> </span><span class="m">11</span><span class="w"> </span>&gt;<span class="w"> </span>debian/compat
</code></pre></div>

<p>Le second contient ceci :</p>
<div class="language-text-only codehilite"><pre><span/><code>memcached (0.0-0) UNRELEASED; urgency=medium

  * Fake entry

 -- Happy Packager &lt;happy@example.com&gt;  Tue, 19 Apr 2016 22:27:05 +0200
</code></pre></div>

<p>La seule information d’importance est le nom du paquet source,
<code>memcached</code>, sur la première ligne. Toutes les autres informations
sont sans influence sur les paquets créés.</p>
<h2 id="le-fichier-de-controle">Le fichier de contrôle</h2>
<p><code>debian/control</code> décrit les méta-données à propos du paquet source et
des paquets binaires. Un bloc est dédié à chacun d’eux.</p>
<div class="language-debian-control-file codehilite"><pre><span/><code><span class="k">Source</span><span class="p">:</span><span class="w"> </span><span class="s">memcached</span>
<span class="k">Maintainer</span><span class="p">:</span><span class="w"> </span>Vincent Bernat <span class="gs">&lt;bernat@debian.org&gt;</span>

<span class="k">Package</span><span class="p">:</span><span class="w"> </span><span class="s">memcached</span>
<span class="k">Architecture</span><span class="p">:</span><span class="w"> </span><span class="s">any</span>
<span class="k">Description</span><span class="gs">: high-performance memory object caching system</span>
</code></pre></div>

<p>Le paquet source est <code>memcached</code>. Il faut utiliser le même nom que
dans le fichier <code>debian/changelog</code>.</p>
<p>Un seul paquet binaire est créé : <code>memcached</code>. Par la suite, si vous
voyez <code>memcached</code>, il s’agit du nom du paquet binaire. Le champ
<code>Architecture</code> doit être soit <code>any</code>, soit <code>all</code>. Ce dernier est
utilisé exclusivement si tous les fichiers sont indépendants de
l’architecture matérielle. Dans le doute, il suffit de mettre <code>any</code>.</p>
<p>Le champ <code>Description</code> contient une courte description du paquet
binaire.</p>
<h2 id="la-recette">La recette</h2>
<p>Le dernier fichier à rédiger est <code>debian/rules</code>. Il s’agit de la
recette du paquet. Nous avons besoin de télécharger <em>memcached</em>, le
construire et installer son arborescence dans <code>debian/memcached/</code> :</p>
<div class="language-makefile codehilite"><pre><span/><code><span class="c">#!/usr/bin/make -f</span>

<span class="nv">DISTRIBUTION</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">$(</span>shell<span class="w"> </span>sed<span class="w"> </span>-n<span class="w"> </span><span class="s2">"s/^VERSION_CODENAME=//p"</span><span class="w"> </span>/etc/os-release<span class="k">)</span>
<span class="nv">VERSION</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span>.6.6
<span class="nv">PACKAGEVERSION</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">$(</span>VERSION<span class="k">)</span>-0~<span class="k">$(</span>DISTRIBUTION<span class="k">)</span><span class="m">0</span>
<span class="nv">TARBALL</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>memcached-<span class="k">$(</span>VERSION<span class="k">)</span>.tar.gz
<span class="nv">URL</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>http://www.memcached.org/files/<span class="k">$(</span>TARBALL<span class="k">)</span>

<span class="nf">%</span><span class="o">:</span>
<span class="w">    </span>dh<span class="w"> </span><span class="nv">$@</span>

<span class="nf">override_dh_auto_clean</span><span class="o">:</span>
<span class="nf">override_dh_auto_test</span><span class="o">:</span>
<span class="nf">override_dh_auto_build</span><span class="o">:</span>
<span class="nf">override_dh_auto_install</span><span class="o">:</span>
<span class="w">    </span>wget<span class="w"> </span>-N<span class="w"> </span>--progress<span class="o">=</span>dot:mega<span class="w"> </span><span class="k">$(</span>URL<span class="k">)</span>
<span class="w">    </span>tar<span class="w"> </span>--strip-components<span class="o">=</span><span class="m">1</span><span class="w"> </span>-xf<span class="w"> </span><span class="k">$(</span>TARBALL<span class="k">)</span>
<span class="w">    </span>./configure<span class="w"> </span>--prefix<span class="o">=</span>/usr
<span class="w">    </span>make
<span class="w">    </span>make<span class="w"> </span>install<span class="w"> </span><span class="nv">DESTDIR</span><span class="o">=</span>debian/memcached

<span class="nf">override_dh_gencontrol</span><span class="o">:</span>
<span class="w">    </span>dh_gencontrol<span class="w"> </span>--<span class="w"> </span>-v<span class="k">$(</span>PACKAGEVERSION<span class="k">)</span>
</code></pre></div>

<p>Les cibles vides <code>override_dh_auto_clean</code>, <code>override_dh_auto_test</code> et
<code>override_dh_auto_build</code> permettent de s’assurer que <em>debhelper</em> ne
fera rien de « magique ». La cible <code>override_dh_gencontrol</code> permet de
spécifier la version<sup id="fnref:version"><a class="footnote-ref" href="#fn:version">4</a></sup> sans avoir à tenir à jour
<code>debian/changelog</code>. Cette recette est très similaire à ce qui aurait
été écrit pour <code>fpm</code> :</p>
<div class="language-bash codehilite"><pre><span/><code><span class="nv">DISTRIBUTION</span><span class="o">=</span><span class="k">$(</span>sed<span class="w"> </span>-n<span class="w"> </span><span class="s2">"s/^VERSION_CODENAME=//p"</span><span class="w"> </span>/etc/os-release<span class="k">)</span>
<span class="nv">VERSION</span><span class="o">=</span><span class="m">1</span>.6.6
<span class="nv">PACKAGEVERSION</span><span class="o">=</span><span class="si">${</span><span class="nv">VERSION</span><span class="si">}</span>-0~<span class="si">${</span><span class="nv">DISTRIBUTION</span><span class="si">}</span><span class="m">0</span>
<span class="nv">TARBALL</span><span class="o">=</span>memcached-<span class="si">${</span><span class="nv">VERSION</span><span class="si">}</span>.tar.gz
<span class="nv">URL</span><span class="o">=</span>http://www.memcached.org/files/<span class="si">${</span><span class="nv">TARBALL</span><span class="si">}</span>

wget<span class="w"> </span>-N<span class="w"> </span>--progress<span class="o">=</span>dot:mega<span class="w"> </span><span class="si">${</span><span class="nv">URL</span><span class="si">}</span>
tar<span class="w"> </span>--strip-components<span class="o">=</span><span class="m">1</span><span class="w"> </span>-xf<span class="w"> </span><span class="si">${</span><span class="nv">TARBALL</span><span class="si">}</span>
./configure<span class="w"> </span>--prefix<span class="o">=</span>/usr
make
make<span class="w"> </span>install<span class="w"> </span><span class="nv">DESTDIR</span><span class="o">=</span>/tmp/installdir

<span class="c1"># Build the final package</span>
fpm<span class="w"> </span>-s<span class="w"> </span>dir<span class="w"> </span>-t<span class="w"> </span>deb<span class="w"> </span><span class="se">\</span>
<span class="w">    </span>-n<span class="w"> </span>memcached<span class="w"> </span><span class="se">\</span>
<span class="w">    </span>-v<span class="w"> </span><span class="si">${</span><span class="nv">PACKAGEVERSION</span><span class="si">}</span><span class="w"> </span><span class="se">\</span>
<span class="w">    </span>-C<span class="w"> </span>/tmp/installdir<span class="w"> </span><span class="se">\</span>
<span class="w">    </span>--description<span class="w"> </span><span class="s2">"high-performance memory object caching system"</span>
</code></pre></div>

<p>Vous pouvez lire le résultat final sur <a href="https://github.com/vincentbernat/pragmatic-debian-packages/tree/master/memcached-basic/debian">GitHub</a> et
le construire avec la commande <code>dpkg-buildpackage -us -uc -b</code> ou avec
<code>GIT_PBUILDER_OPTIONS=--use-network=yes DIST=bionic git-pbuilder -us
-uc -b</code> si vous avez déjà mis en place un outil tel que <code>pbuilder</code>.</p>
<h1 id="ceinture-jaune">Ceinture jaune</h1>
<p>À partir de là, il est possible d’inclure quelques
améliorations. <strong>Aucune n’est essentielle</strong> mais le gain est
suffisamment intéressant pour justifier l’effort.</p>
<h2 id="les-dependances-sources">Les dépendances sources</h2>
<p>Notre recette initiale ne fonctionne que si nous disposons déjà de
<code>wget</code> et de <code>libevent-dev</code>. Ces paquets ne sont pas présents sur tous
les systèmes. Il est assez aisé de spécifier ces dépendances en
ajoutant un champ <code>Build-Depends</code> dans <code>debian/control</code> :</p>
<div class="language-debian-control-file codehilite"><pre><span/><code><span class="k">Source</span><span class="p">:</span><span class="w"> </span><span class="s">memcached</span>
<span class="k">Build-Depends</span><span class="p">:</span><span class="w"> </span><span class="nf">debhelper</span> <span class="p">(</span><span class="o">&gt;=</span><span class="w"> </span><span class="m">11</span><span class="p">)</span>,
<span class="w"> </span>              <span class="nf">wget</span>, <span class="nf">ca-certificates</span>,
<span class="w"> </span>              <span class="nf">libevent-dev</span>
</code></pre></div>

<p>Il faut toujours spécifier <code>debhelper (&gt;= 11)</code> car son utilisation est
centrale dans <code>debian/rules</code>. Il n’y a pas besoin de dépendre de
<code>make</code> ou d’un compilateur C car le paquet <code>build-essential</code> est
considéré comme toujours présent et il les fournit indirectement.
<code>dpkg-buildpackage</code> se plaindra si une des dépendances est manquante.
Pour installer sans peine ces paquets, par exemple depuis un
environnement d’intégration continue, vous pouvez utiliser la commande
suivante<sup id="fnref:devscripts"><a class="footnote-ref" href="#fn:devscripts">5</a></sup> :</p>
<div class="language-bash codehilite"><pre><span/><code>mk-build-deps<span class="w"> </span><span class="se">\</span>
<span class="w">    </span>-t<span class="w"> </span><span class="s1">'apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends -qqy'</span><span class="w"> </span><span class="se">\</span>
<span class="w">    </span>-i<span class="w"> </span>-r<span class="w"> </span>debian/control
</code></pre></div>

<p>Il est aussi intéressant de se pencher sur des outils tels que
<a href="https://pbuilder-team.pages.debian.net/pbuilder/" title="pbuilder user's manual">pbuilder</a>, <a href="https://wiki.debian.org/sbuild" title="sbuild page on Debian Wiki">sbuild</a> ou <a href="https://www.uhoreg.ca/programming/debian/whalebuilder" title="Debian package builder using Docker">whalebuilder</a>. Ils permettent de
construire des paquets dans un environnement minimal et isolé.</p>
<h2 id="les-dependances-binaires">Les dépendances binaires</h2>
<p>Si le paquet ainsi construit est installé sur une machine vierge,
<em>memcached</em> refusera de démarrer en raison de l’absence de
<em>libevent</em>. Il est possible d’exprimer cette dépendance en ajoutant un
champ <code>Depends</code> dans le fichier <code>debian/control</code>. De plus, dans le cas
des bibliothèques dynamiques, ces dépendances peuvent être générées
automatiquement en utilisant des variables de substitution :</p>
<div class="language-debian-control-file codehilite"><pre><span/><code><span class="k">Package</span><span class="p">:</span><span class="w"> </span><span class="s">memcached</span>
<span class="k">Depends</span><span class="p">:</span><span class="w"> </span><span class="o">$</span><span class="p">{</span><span class="ni">misc</span><span class="p">:</span>Depends<span class="p">}</span>, <span class="o">$</span><span class="p">{</span><span class="ni">shlibs</span><span class="p">:</span>Depends<span class="p">}</span>
</code></pre></div>

<p>Le paquet construit contiendra les informations suivantes :</p>
<div class="language-bash-session codehilite"><pre><span/><code><span class="gp">$ </span>dpkg<span class="w"> </span>-I<span class="w"> </span>../memcached_1.6.6-0<span class="se">\~</span>buster0_amd64.deb<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>Depends
<span class="go"> Depends: libc6 (&gt;= 2.17), libevent-2.1-6 (&gt;= 2.1.8-stable)</span>
</code></pre></div>

<h2 id="integration-avec-un-systeme-de-demarrage">Intégration avec un système de démarrage</h2>
<p>La plupart des paquets fournissant un démon incluent une intégration
avec le système de démarrage afin de démarrer le démon au boot ou de
le redémarrer après une mise à jour. Bien que Debian assure la prise
en charge de plusieurs systèmes de démarrage, je pense qu’il est
préférable de se limiter à <strong>systemd</strong>.</p>
<p>Pour fournir un script pour <em>systemd</em>, il convient de placer son
contenu dans <code>debian/memcached.service</code>. Par exemple :</p>
<div class="language-systemd codehilite"><pre><span/><code><span class="k">[Unit]</span>
<span class="na">Description</span><span class="o">=</span><span class="s">memcached daemon</span>
<span class="na">After</span><span class="o">=</span><span class="s">network.target</span>

<span class="k">[Service]</span>
<span class="na">Type</span><span class="o">=</span><span class="s">forking</span>
<span class="na">Environment</span><span class="o">=</span><span class="s">PORT=11211</span>
<span class="na">Environment</span><span class="o">=</span><span class="s">MAXCONN=1024</span>
<span class="na">Environment</span><span class="o">=</span><span class="s">CACHESIZE=64</span>
<span class="na">Environment</span><span class="o">=</span><span class="s">OPTIONS=</span>
<span class="na">ExecStart</span><span class="o">=</span><span class="s">/usr/bin/memcached -d -p $PORT -m $CACHESIZE -c $MAXCONN $OPTIONS</span>
<span class="na">Restart</span><span class="o">=</span><span class="s">on-failure</span>
<span class="na">User</span><span class="o">=</span><span class="s">_memcached</span>
<span class="na">DynamicUser</span><span class="o">=</span><span class="s">yes</span>

<span class="k">[Install]</span>
<span class="na">WantedBy</span><span class="o">=</span><span class="s">multi-user.target</span>
</code></pre></div>

<p>La directive <code>Type</code> est la plus importante. Nous avons utilisé
<code>forking</code> car <em>memcached</em> est démarré à l’aide de l’option <code>-d</code>. Cela
lui indique de se mettre en arrière-plan lorsqu’il est prêt à accepter
des requêtes. Les autres possibilités sont <code>notify</code> pour un démon
spécifiquement prévu pour fonctionner avec <em>systemd</em> ou <code>simple</code> pour
un démon ne passant pas en arrière-plan.</p>
<p>Si un utilisateur veut personnaliser l’une des directives
<code>Environment</code>, il peut utiliser <code>systemctl edit memcached.service</code>
pour créer le fichier
<code>/etc/systemd/system/memcached.service.d/override.conf</code> qui va
surcharger les définitions du script fourni par le paquet. <code>systemctl
cat memcached.service</code> permet d’obtenir la définition finale du
service.</p>
<p>La directive <code>DynamicUser</code> est particulièrement intéressante. Elle
indique à <em>systemd</em> de créer dynamiquement l’utilisateur
<code>_memcached</code><sup id="fnref:naming"><a class="footnote-ref" href="#fn:naming">6</a></sup> qui sera utilisé pour faire tourner le démon.
Cela nous libère de la gestion d’un utilisateur système !</p>
<p>Le résultat final est disponible sur
<a href="https://github.com/vincentbernat/pragmatic-debian-packages/tree/master/memcached-intermediate/debian">GitHub</a> et peut être testé avec la
commande <code>dpkg-buildpackage -us -uc -b</code>.</p>
<h1 id="ceinture-verte">Ceinture verte</h1>
<p>Il est possible d’exploiter certaines capacités de <em>debhelper</em> pour
<strong>réduire la taille</strong> du fichier <code>debian/rules</code> et pour le rendre
<strong>plus déclaratif</strong>. Cette section est totalement optionnelle : vous
pouvez la sauter si besoin.</p>
<h2 id="banalites">Banalités</h2>
<p>Il y a <strong>quatre étapes</strong> dans la construction d’un paquet Debian :</p>
<ol>
<li>
<p><code>debian/rules clean</code> va <strong>nettoyer</strong> l’arborescence pour revenir
    dans son état initial.</p>
</li>
<li>
<p><code>debian/rules build</code> doit <strong>construire</strong> le logiciel. Pour quelque
    chose de basé sur <em>autoconf</em>, comme <em>memcached</em>, il s’agit
    essentiellement d’exécuter <code>./configure &amp;&amp; make</code>.</p>
</li>
<li>
<p><code>debian/rules install</code> doit <strong>installer</strong> l’arborescence de chaque
    paquet binaire dans le répertoire approprié. Pour des logiciels
    basés sur <em>autoconf</em>, il s’agit d’exécuter <code>make install
    DESTDIR=debian/memcached</code>.</p>
</li>
<li>
<p><code>debian/rules binary</code> doit <strong>empaqueter</strong> les différentes
    arborescences en paquets binaires.</p>
</li>
</ol>
<p>Il ne faut pas écrire directement chacune de ces cibles. L’utilitaire
<code>dh</code>, un composant de <em>debhelper</em>, va faire la majeure partie du
boulot. Le fichier <code>debian/rules</code> minimaliste suivant suffit pour accomplir
cette tâche pour de nombreux paquets sources :</p>
<div class="language-makefile codehilite"><pre><span/><code><span class="c">#!/usr/bin/make -f</span>
<span class="nf">%</span><span class="o">:</span>
<span class="w">    </span>dh<span class="w"> </span><span class="nv">$@</span>
</code></pre></div>

<p>Pour chacune des quatre cibles décrites ci-dessus, vous pouvez
exécuter <code>dh --no-act</code> pour voir les utilitaires invoqués. Par
exemple :</p>
<div class="language-bash-session codehilite"><pre><span/><code><span class="gp">$ </span>dh<span class="w"> </span>build<span class="w"> </span>--no-act
<span class="go">   dh_testdir</span>
<span class="go">   dh_update_autotools_config</span>
<span class="go">   dh_auto_configure</span>
<span class="go">   dh_auto_build</span>
<span class="go">   dh_auto_test</span>
</code></pre></div>

<p>Chacun de ces utilitaires dispose d’une page de manuel. Ceux
commençant par <code>dh_auto</code> sont un peu « magiques ». Par exemple,
<code>dh_auto_configure</code> va tenter de configurer automatiquement le
logiciel avant l’étape de construction. Selon les cas, il peut
invoquer <code>./configure</code>, <code>cmake</code> ou <code>Makefile.PL</code>.</p>
<p>Si un des utilitaires <code>dh_</code> ne fait pas ce qu’il faut, il est possible
de le remplacer en déclarant une cible nommée de manière adéquate :</p>
<div class="language-makefile codehilite"><pre><span/><code><span class="nf">override_dh_auto_configure</span><span class="o">:</span>
<span class="w">    </span>./configure<span class="w"> </span>--with-some-grog
</code></pre></div>

<p>Chaque utilitaire est également configurable via des options. Ainsi,
il est possible de modifier leurs comportements en définissant la cible
correspondante et en invoquant l’utilitaire manuellement :</p>
<div class="language-makefile codehilite"><pre><span/><code><span class="nf">override_dh_auto_configure</span><span class="o">:</span>
<span class="w">    </span>dh_auto_configure<span class="w"> </span>--<span class="w"> </span>--with-some-grog
</code></pre></div>

<p>Ainsi, <code>./configure</code> sera appelé avec l’option <code>--with-some-grog</code> mais
aussi avec des options par défaut telles que <code>--prefix=/usr</code>. Il y a
une page de manuel pour chacun de ces outils.</p>
<p>Dans l’exemple initial de <em>memcached</em>, ces cibles « magiques » sont
surchargées. <code>dh_auto_clean</code>, <code>dh_auto_configure</code> et <code>dh_auto_build</code>
ont été neutralisées pour éviter tout comportement
inattendu. <code>dh_auto_install</code> a été détournée pour exécuter l’intégralité
de la construction de l’arborescence cible. De plus, le comportement
de <code>dh_gencontrol</code> a été modifié en lui fournissant le numéro de version
désiré plutôt que de le laisser regarder dans <code>debian/changelog</code>.</p>
<h2 id="construction-automatique">Construction automatique</h2>
<p><em>memcached</em> utilisant <em>autoconf</em>, <code>dh</code> <strong>sait comment le construire</strong> :
<code>./configure &amp;&amp; make &amp;&amp; make install</code>. Il est donc possible de laisser
<code>dh</code> faire la majeure partie du boulot avec le fichier debian/rules
suivant :</p>
<div class="language-makefile codehilite"><pre><span/><code><span class="c">#!/usr/bin/make -f</span>

<span class="nv">DISTRIBUTION</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">$(</span>shell<span class="w"> </span>sed<span class="w"> </span>-n<span class="w"> </span><span class="s2">"s/^VERSION_CODENAME=//p"</span><span class="w"> </span>/etc/os-release<span class="k">)</span>
<span class="nv">VERSION</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span>.6.6
<span class="nv">PACKAGEVERSION</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">$(</span>VERSION<span class="k">)</span>-0~<span class="k">$(</span>DISTRIBUTION<span class="k">)</span><span class="m">0</span>
<span class="nv">TARBALL</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>memcached-<span class="k">$(</span>VERSION<span class="k">)</span>.tar.gz
<span class="nv">URL</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>http://www.memcached.org/files/<span class="k">$(</span>TARBALL<span class="k">)</span>

<span class="nf">%</span><span class="o">:</span>
<span class="w">    </span>dh<span class="w"> </span><span class="nv">$@</span><span class="w"> </span>--with<span class="w"> </span>systemd

<span class="nf">override_dh_update_autotools_config</span><span class="o">:</span>
<span class="w">    </span>wget<span class="w"> </span>-N<span class="w"> </span>--progress<span class="o">=</span>dot:mega<span class="w"> </span><span class="k">$(</span>URL<span class="k">)</span>
<span class="w">    </span>tar<span class="w"> </span>--strip-components<span class="o">=</span><span class="m">1</span><span class="w"> </span>-xf<span class="w"> </span><span class="k">$(</span>TARBALL<span class="k">)</span>

<span class="nf">override_dh_auto_test</span><span class="o">:</span>
<span class="c">    # Don't run the whitespace test</span>
<span class="w">    </span>rm<span class="w"> </span>t/whitespace.t
<span class="w">    </span>dh_auto_test

<span class="nf">override_dh_gencontrol</span><span class="o">:</span>
<span class="w">    </span>dh_gencontrol<span class="w"> </span>--<span class="w"> </span>-v<span class="k">$(</span>PACKAGEVERSION<span class="k">)</span>
</code></pre></div>

<p>La cible <code>dh_update_autotools_config</code> est détournée pour effectuer le
téléchargement et la mise en place de l’arborescence. Ni
<code>dh_auto_configure</code>, ni <code>dh_auto_build</code> ne sont modifiés. <code>dh</code>
appellera <code>./configure</code> avec les options appropriées puis <code>make</code>.
<code>dh_auto_test</code> doit exécuter la suite de tests de <em>memcached</em>.
Toutefois, un des tests échoue en raison d’un fichier dans le
répertoire <code>debian/</code>. Nous supprimons ce test récalcitrant et
invoquons manuellement <code>dh_auto_test</code>. <code>dh_auto_install</code> n’est pas
surchargé et <code>dh</code> exécutera alors une variante de <code>make install</code>.</p>
<p>Afin de mieux apprécier la différence, la voici sous forme de rustine :</p>
<div class="language-diff codehilite"><pre><span/><code><span class="gd">--- memcached-intermediate/debian/rules 2019-05-31 07:52:40.908868035 +0200</span>
<span class="gi">+++ memcached/debian/rules      2019-05-31 07:28:17.404380064 +0200</span>
<span class="gu">@@ -9,15 +9,14 @@</span>
<span class="w"> </span>%:
<span class="w"> </span>   dh $@

<span class="gd">-override_dh_auto_clean:</span>
<span class="gd">-override_dh_auto_test:</span>
<span class="gd">-override_dh_auto_build:</span>
<span class="gd">-override_dh_auto_install:</span>
<span class="gi">+override_dh_update_autotools_config:</span>
<span class="w"> </span>   wget -N --progress=dot:mega $(URL)
<span class="w"> </span>   tar --strip-components=1 -xf $(TARBALL)
<span class="gd">-   ./configure --prefix=/usr</span>
<span class="gd">-   make</span>
<span class="gd">-   make install DESTDIR=debian/memcached</span>
<span class="gi">+</span>
<span class="gi">+override_dh_auto_test:</span>
<span class="gi">+   # Don't run the whitespace test</span>
<span class="gi">+   rm t/whitespace.t</span>
<span class="gi">+   dh_auto_test</span>

<span class="w"> </span>override_dh_gencontrol:
<span class="w"> </span>   dh_gencontrol -- -v$(PACKAGEVERSION)
</code></pre></div>

<p>Vous avez le choix de laisser <code>dh</code> faire une partie du travail ou
non. Il est généralement possible de partir d’un <code>debian/rules</code>
minimal et de surcharger uniquement quelques cibles.</p>
<h2 id="fichiers-supplementaires">Fichiers supplémentaires</h2>
<p>Bien que <code>make install</code> ait installé les fichiers essentiels pour
<em>memcached</em>, il est parfois nécessaire de copier quelques fichiers
supplémentaires dans le paquet binaire. Pour ce faire, il est possible
d’utiliser <code>cp</code> ou encore de déclarer les fichiers à copier :</p>
<ul>
<li>les fichiers listés dans <code>debian/memcached.docs</code> seront copiés dans
   <code>/usr/share/doc/memcached</code> par <code>dh_installdocs</code> ;</li>
<li>les fichiers listés dans <code>debian/memcached.examples</code> seront copiés dans
   <code>/usr/share/doc/memcached/examples</code> par <code>dh_installexamples</code> ;</li>
<li>les fichiers listés dans <code>debian/memcached.manpages</code> seront copiés
   dans le sous-répertoire approprié de <code>/usr/share/man</code> par
   <code>dh_installman</code>.</li>
</ul>
<p>Voici un exemple pour <code>debian/memcached.docs</code> :</p>
<div class="language-text-only codehilite"><pre><span/><code>doc/*.txt
</code></pre></div>

<p>Si vous avez besoin de copier des fichiers à un endroit arbitraire, il
est possible de lister ceux-ci ainsi que leur répertoire cible dans le
fichier <code>debian/memcached.install</code>. <code>dh_install</code> se chargera de la
copie. Par exemple :</p>
<div class="language-text-only codehilite"><pre><span/><code>scripts/memcached-tool usr/bin
</code></pre></div>

<p>L’utilisation de ces fichiers permet une description <strong>plus
déclarative</strong> de la recette. Il s’agit d’une histoire de goût et vous
pouvez tout à fait utiliser <code>cp</code> à la place. Le résultat final est
visible sur <a href="https://github.com/vincentbernat/pragmatic-debian-packages/tree/master/memcached/debian">GitHub</a>.</p>
<h1 id="autres-exemples">Autres exemples</h1>
<p>Le <a href="https://github.com/vincentbernat/pragmatic-debian-packages" title="Dépôt Git rempli de paquets Debian simples à comprendre">dépôt Git</a> comprend d’autres exemples. Ils suivent tous
le même schéma et mettent en œuvre les techniques décrites dans les
sections précédentes :</p>
<ul>
<li><code>dh_update_autotools_config</code> est surchargée pour télécharger et mettre en place les sources ;</li>
<li><code>dh_gencontrol</code> est modifiée pour fixer la version du paquet.</li>
</ul>
<p>Il y a notamment des exemples de démons en <a href="https://github.com/vincentbernat/pragmatic-debian-packages/tree/master/riemann/debian">Java</a>, <a href="https://github.com/vincentbernat/pragmatic-debian-packages/tree/master/etcd/debian">Go</a>,
<a href="https://github.com/vincentbernat/pragmatic-debian-packages/tree/master/puppetboard/debian">Python</a> et <a href="https://github.com/vincentbernat/pragmatic-debian-packages/tree/master/kiwiirc/debian">Node.js</a>. Le but de ces exemples est de démontrer que
l’utilisation des outils Debian est relativement simple. Mission accomplie ?</p>
<div class="admonition">
<p class="admonition-title">Mise à jour (05.2019)</p>
<p>Ce guide a été mis à jour pour utiliser
<code>override_dh_update_autotools_config</code> pour télécharger des fichiers à la
place de <code>override_dh_auto_clean</code>. Cela permet une intégration plus simple
avec la plupart des outils de construction, tels que <code>pbuilder</code> et <code>sbuild</code>.</p>
</div>
<div class="footnote">
<hr/>
<ol>
<li id="fn:difficulty">
<p>La mémoire collective est toujours marquée par la
glorieuse époque précédant l’introduction de
<em>debhelper</em> 7.0.50 (circa 2009). La création du fichier
<code>debian/rules</code> était alors particulièrement
laborieuse. Toutefois, de nos jours, le squelette est
devenu minimal. <a class="footnote-backref" href="#fnref:difficulty" title="Jump back to footnote 1 in the text">↩</a></p>
</li>
<li id="fn:fpm">
<p>La complexité n’est pas la seule raison de ce choix : les
outils alternatifs proposent également la création de paquets
RPM, ce que les outils Debian ne permettent pas. <a class="footnote-backref" href="#fnref:fpm" title="Jump back to footnote 2 in the text">↩</a></p>
</li>
<li id="fn:compat">
<p>Ce niveau de compatibilité est disponible à partir de
Debian 9 et d’Ubuntu Bionic. Il couvre donc les distributions
modernes. Cependant, il souffre d’un <a href="https://bugs.debian.org/887904" title="dh_installsystemd will unmask services *after* an attempt to start them">problème empêchant le
démarrage d’un service</a> lorsqu’un paquet est installé,
désinstallé puis réinstallé de nouveau. Le niveau 10 augmente
sensiblement la complexité. Si possible, vous pouvez opter pour la
version 12, disponible depuis Debian 10 et Ubuntu Focal. <a class="footnote-backref" href="#fnref:compat" title="Jump back to footnote 3 in the text">↩</a></p>
</li>
<li id="fn:version">
<p>Il y a différentes façons de numéroter les versions d’un
paquet. La façon proposée ici n’est pas plus mauvaise
qu’une autre pour Ubuntu. Pour Debian, elle ne couvre pas
les mises à jour entre deux versions de la
distribution. De nos jours, il est cependant plutôt
courant de réinstaller un système plutôt que de le mettre
à jour. <a class="footnote-backref" href="#fnref:version" title="Jump back to footnote 4 in the text">↩</a></p>
</li>
<li id="fn:devscripts">
<p>Les paquets <code>devscripts</code> et <code>equivs</code> sont alors nécessaires. <a class="footnote-backref" href="#fnref:devscripts" title="Jump back to footnote 5 in the text">↩</a></p>
</li>
<li id="fn:naming">
<p>La charte Debian ne se prononce pas sur la convention à
utiliser. Il est courant de préfixer le nom du démon avec un tiret
bas (comme dans les BSD). Un autre usage courant est d’utiliser
<code>Debian-</code> comme préfixe. Cette dernière méthode a l’inconvénient
de produire un nom d’utilisateur trop long pour être visible dans
les utilitaires comme <code>top</code> et <code>ps</code>.</p>
<p>Si la directive <code>User</code> n’est pas précisée, <em>systemd</em> utilise
simplement le nom du service comme nom d’utilisateur. Si cela vous
convient, vous pouvez alors omettre cette directive. <a class="footnote-backref" href="#fnref:naming" title="Jump back to footnote 6 in the text">↩</a></p>
</li>
</ol>
</div>
      </div>
    </content>
  </entry>
  <entry>
    <title type="html">Empaquetage d'un module tiers pour Debian avec DKMS</title>
    <author><name>Vincent Bernat</name></author>
    <link href="https://vincent.bernat.ch/fr/blog/2018-empaquetage-pilote-debian-dkms" rel="alternate"/>
    <link href="https://vincent.bernat.ch/fr/blog/2018-empaquetage-pilote-debian-dkms#isso-thread" rel="replies" type="text/html"/>
    <updated>2018-03-07T16:38:52Z</updated>
    <id>http://www.luffy.cx/fr/blog/2018-empaquetage-pilote-debian-dkms.html</id>

    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<blockquote>
<p><a href="https://github.com/dkms-project/dkms" title="Dynamic Kernel Module Support sur GitHub"><abbr title="Dynamic Kernel Module Support">DKMS</abbr></a> est un système conçu pour permettre la mise à jour
individuelle de modules noyau sans changer le noyau en entier. Il
est également très facile de reconstruire des modules lorsque vous
mettez à jour le noyau.</p>
</blockquote>
<p>Sur les systèmes de type Debian<sup id="fnref:rpm"><a class="footnote-ref" href="#fn:rpm">1</a></sup>, <em><abbr title="Dynamic Kernel Module Support">DKMS</abbr></em> permet l’installation de
différents pilotes, de <a href="https://packages.debian.org/sid/zfs-dkms" title="Paquet pour le module ZFS on Linux pour Debian">ZFS</a> aux modules
<a href="https://packages.debian.org/sid/virtualbox-dkms" title="Module noyau VirtualBox kernel pour Debian">VirtualBox</a> ou <a href="https://packages.debian.org/sid/nvidia-kernel-dkms" title="Pilote NVIDIA pour Debian">NVIDIA</a>. Ces modules externes ne sont pas distribués sous forme
binaire : une fois installés, ils doivent être compilés pour votre
noyau actuel. Tout se fait automatiquement :</p>
<div class="language-bash-session codehilite"><pre><span/><code><span class="gp"># </span>apt<span class="w"> </span>install<span class="w"> </span>zfs-dkms
<span class="go">Reading package lists... Done</span>
<span class="go">Building dependency tree</span>
<span class="go">Reading state information... Done</span>
<span class="go">The following additional packages will be installed:</span>
<span class="go">  binutils cpp cpp-6 dkms fakeroot gcc gcc-6 gcc-6-base libasan3 libatomic1 libc-dev-bin libc6-dev</span>
<span class="go">  libcc1-0 libcilkrts5 libfakeroot libgcc-6-dev libgcc1 libgomp1 libisl15 libitm1 liblsan0 libmpc3</span>
<span class="go">  libmpfr4 libmpx2 libnvpair1linux libquadmath0 libstdc++6 libtsan0 libubsan0 libuutil1linux libzfs2linux</span>
<span class="go">  libzpool2linux linux-compiler-gcc-6-x86 linux-headers-4.9.0-6-amd64 linux-headers-4.9.0-6-common</span>
<span class="go">  linux-headers-amd64 linux-kbuild-4.9 linux-libc-dev make manpages manpages-dev patch spl spl-dkms</span>
<span class="go">  zfs-zed zfsutils-linux</span>
<span class="go">[…]</span>
<span class="go">3 upgraded, 44 newly installed, 0 to remove and 3 not upgraded.</span>
<span class="go">Need to get 42.1 MB of archives.</span>
<span class="go">After this operation, 187 MB of additional disk space will be used.</span>
<span class="go">Do you want to continue? [Y/n]</span>
<span class="go">[…]</span>
<span class="gp"># </span>dkms<span class="w"> </span>status
<span class="go">spl, 0.6.5.9, 4.9.0-6-amd64, x86_64: installed</span>
<span class="go">zfs, 0.6.5.9, 4.9.0-6-amd64, x86_64: installed</span>
<span class="gp"># </span>modinfo<span class="w"> </span>zfs<span class="w"> </span><span class="p">|</span><span class="w"> </span>head
<span class="go">filename:       /lib/modules/4.9.0-6-amd64/updates/dkms/zfs.ko</span>
<span class="go">version:        0.6.5.9-5</span>
<span class="go">license:        CDDL</span>
<span class="go">author:         OpenZFS on Linux</span>
<span class="go">description:    ZFS</span>
<span class="go">srcversion:     42C4AB70887EA26A9970936</span>
<span class="go">depends:        spl,znvpair,zcommon,zunicode,zavl</span>
<span class="go">retpoline:      Y</span>
<span class="go">vermagic:       4.9.0-6-amd64 SMP mod_unload modversions</span>
<span class="go">parm:           zvol_inhibit_dev:Do not create zvol device nodes (uint)</span>
</code></pre></div>

<p>Lors de l’installation d’un nouveau noyau, la compilation du module
est automatiquement déclenchée.</p>
<h1 id="construction-dun-paquet-compatible-dkms">Construction d’un paquet compatible <abbr title="Dynamic Kernel Module Support">DKMS</abbr></h1>
<p>Supposons que vous avez mis la main sur un serveur avec une carte
réseau <a href="https://www.intel.com/content/www/us/en/products/sku/95260/intel-ethernet-network-adapter-xxv710da2/specifications.html" title="Intel Ethernet Network Adapter XXV710-DA2">Intel XXV710-DA2</a>. Cette carte est gérée par le pilote
<code>i40e</code>. Malheureusement, elle n’est prise en charge que depuis Linux 4.10 et vous utilisez un noyau 4.9 issu de Debian Stretch. <em><abbr title="Dynamic Kernel Module Support">DKMS</abbr></em>
fournit ici une solution simple !</p>
<p>Téléchargez les <a href="https://www.intel.com/content/www/us/en/download/18026/intel-network-adapter-driver-for-pcie-40-gigabit-ethernet-network-connections-under-linux.html" title="Intel Network Adapter Driver for PCIe 40 Gigabit Ethernet Network Connections Under Linux">sources du pilote chez Intel</a>,
décompressez-les dans un répertoire et ajoutez un sous-répertoire
<code>debian/</code> avec les fichiers suivants :</p>
<ul>
<li>
<p><code>debian/changelog</code>:</p>
<div class="language-text-only codehilite"><pre><span/><code>i40e-dkms (2.4.6-0) stretch; urgency=medium

  * Initial package.

 -- Vincent Bernat &lt;bernat@debian.org&gt;  Tue, 27 Feb 2018 17:20:58 +0100
</code></pre></div>

</li>
<li>
<p><code>debian/control</code>:</p>
<div class="language-debian-control-file codehilite"><pre><span/><code><span class="k">Source</span><span class="p">:</span><span class="w"> </span><span class="s">i40e-dkms</span>
<span class="k">Maintainer</span><span class="p">:</span><span class="w"> </span>Vincent Bernat <span class="gs">&lt;bernat@debian.org&gt;</span>
<span class="k">Build-Depends</span><span class="p">:</span><span class="w"> </span><span class="nf">debhelper</span> <span class="p">(</span><span class="o">&gt;=</span><span class="w"> </span><span class="m">9</span><span class="p">)</span>, <span class="nf">dkms</span>

<span class="nf">Package</span><span class="err">:</span> <span class="nf">i40e-dkms</span>
<span class="k">Architecture</span><span class="p">:</span><span class="w"> </span><span class="s">all</span>
<span class="k">Depends</span><span class="p">:</span><span class="w"> </span><span class="o">$</span><span class="p">{</span><span class="ni">misc</span><span class="p">:</span>Depends<span class="p">}</span>
<span class="k">Description</span><span class="gs">: DKMS source for the Intel i40e network driver</span>
</code></pre></div>

</li>
<li>
<p><code>debian/rules</code>:</p>
<div class="language-makefile codehilite"><pre><span/><code><span class="c">#!/usr/bin/make -f</span>

<span class="cp">include /usr/share/dpkg/pkg-info.mk</span>

<span class="nf">%</span><span class="o">:</span>
<span class="w">        </span>dh<span class="w"> </span><span class="nv">$@</span><span class="w"> </span>--with<span class="w"> </span>dkms

<span class="nf">override_dh_install</span><span class="o">:</span>
<span class="hll"><span class="w">        </span>dh_install<span class="w"> </span>src/*<span class="w"> </span>usr/src/i40e-<span class="k">$(</span>DEB_VERSION_UPSTREAM<span class="k">)</span>/
</span>
<span class="nf">override_dh_dkms</span><span class="o">:</span>
<span class="w">        </span>dh_dkms<span class="w"> </span>-V<span class="w"> </span><span class="k">$(</span>DEB_VERSION_UPSTREAM<span class="k">)</span>

<span class="nf">override_dh_auto_configure</span><span class="o">:</span>
<span class="nf">override_dh_auto_build</span><span class="o">:</span>
<span class="nf">override_dh_auto_test</span><span class="o">:</span>
<span class="nf">override_dh_auto_install</span><span class="o">:</span>
<span class="nf">override_dh_auto_clean</span><span class="o">:</span>
</code></pre></div>

</li>
<li>
<p><code>debian/i40e-dkms.dkms</code>:</p>
<div class="language-ini codehilite"><pre><span/><code><span class="na">PACKAGE_NAME</span><span class="o">=</span><span class="s">"i40e"</span>
<span class="na">PACKAGE_VERSION</span><span class="o">=</span><span class="s">"#MODULE_VERSION#"</span>
<span class="na">BUILT_MODULE_NAME[0]</span><span class="o">=</span><span class="s">"$PACKAGE_NAME"</span>
<span class="na">DEST_MODULE_LOCATION[0]</span><span class="o">=</span><span class="s">"/updates/dkms"</span>
<span class="na">AUTOINSTALL</span><span class="o">=</span><span class="s">"YES"</span>
<span class="na">REMAKE_INITRD</span><span class="o">=</span><span class="s">"YES"</span>
</code></pre></div>

</li>
<li>
<p><code>debian/compat</code>:</p>
<div class="language-text-only codehilite"><pre><span/><code>9
</code></pre></div>

</li>
</ul>
<p>Le fichier <code>debian/changelog</code> permet essentiellement de spécifier la
version du paquet. Celle du pilote est 2.4.6. Par conséquent, nous
utilisons <code>2.4.6-0</code> comme version de paquet. Dans <code>debian/rules</code>, nous
copions les sources du pilote dans <code>/usr/src/i40e-2.4.6</code> (la version
est extraite de <code>debian/changelog</code>).</p>
<p>Le contenu de <code>debian/i40e-dkms.dkms</code> est décrit en détail dans la
<a href="https://manpages.debian.org/dkms.8.html#DKMS.CONF" title="Page de manuel pour dkms(8)">page de manuel <code>dkms(8)</code></a>. Le pilote <code>i40e</code> est assez
standard et <code>dkms</code> sait comment le compiler. Cependant, si un module
noyau ne suit pas les conventions habituelles, c’est le bon endroit
pour remplacer la commande de construction.</p>
<p>Une fois tous les fichiers en place, vous pouvez transformer le
répertoire en un paquet Debian à l’aide, par exemple, de la commande
<code>dpkg-buildpackage</code> command<sup id="fnref:apt"><a class="footnote-ref" href="#fn:apt">2</a></sup>. Vous obtenez un paquet compatible
<em><abbr title="Dynamic Kernel Module Support">DKMS</abbr></em> : <code>i40e-dkms_2.4.6-0_all.deb</code>. Placez le dans votre <a href="/fr/blog/2014-depots-apt-locaux" title="Dépôts APT locaux en entreprise">dépôt
interne</a> et installez-le sur le serveur cible.</p>
<h1 id="eviter-la-phase-de-compilation">Éviter la phase de compilation</h1>
<div class="admonition">
<p class="admonition-title">Mise à jour (03.2024)</p>
<p>Les mainteneurs de <em><abbr title="Dynamic Kernel Module Support">DKMS</abbr></em> ont supprimé la commande <code>dkms mkbmdeb</code>. Cela
concerne les versions à partir de la 2.8.8, y compris celles fournies dans
Debian Bookworm et Ubuntu Noble. Voir <a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1009179" title="Debian bug #1009179">le bug Debian #1009179</a> pour plus d’informations.</p>
</div>
<div class="admonition">
<p class="admonition-title">Mise à jour (09.2026)</p>
<p>Pour la remplacer, vous pouvez utiliser <a href="https://github.com/uecasm/dkms-mkbmdeb" title="Script de remplacement pour dkms mkbmdeb"><code>dkms-mkbmdeb</code></a>, un
script avec les mêmes fonctionnalités. Échangez <code>dkms mkbmdeb</code> avec
<code>dkms-mkbmdeb</code> dans l’exemple ci-dessous. Merci à Gavin !</p>
</div>
<p>Si la présence d’outils de développement sur un serveur en production
vous rend nerveux, il y a une solution ! Depuis la version
2.2.0.3-5<sup id="fnref:version"><a class="footnote-ref" href="#fn:version">3</a></sup>, grâce à <a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=554843#92" title="Debian bug #554843">Thijs Kinkhorst</a>, <code>dkms</code> peut
construire des paquets contenant uniquement les modules
précompilés. Pour chaque version du noyau, un tel paquet peut être
construit via votre système d’intégration :</p>
<div class="language-bash codehilite"><pre><span/><code><span class="nv">KERNEL_VERSION</span><span class="o">=</span><span class="m">4</span>.9.0-6-amd64<span class="w"> </span><span class="c1"># could be a Jenkins parameter</span>
apt<span class="w"> </span>-qyy<span class="w"> </span>install<span class="w"> </span><span class="se">\</span>
<span class="w">      </span>i40e-dkms<span class="w"> </span><span class="se">\</span>
<span class="w">      </span>linux-image-<span class="si">${</span><span class="nv">KERNEL_VERSION</span><span class="si">}</span><span class="w"> </span><span class="se">\</span>
<span class="w">      </span>linux-headers-<span class="si">${</span><span class="nv">KERNEL_VERSION</span><span class="si">}</span>

<span class="nv">DRIVER_VERSION</span><span class="o">=</span><span class="k">$(</span>dkms<span class="w"> </span>status<span class="w"> </span>i40e<span class="w"> </span><span class="p">|</span><span class="w"> </span>awk<span class="w"> </span>-F<span class="s1">', '</span><span class="w"> </span><span class="s1">'{print $2}'</span><span class="k">)</span>
<span class="hll">dkms<span class="w"> </span>mkbmdeb<span class="w"> </span>i40e/<span class="si">${</span><span class="nv">DRIVER_VERSION</span><span class="si">}</span><span class="w"> </span>-k<span class="w"> </span><span class="si">${</span><span class="nv">KERNEL_VERSION</span><span class="si">}</span>
</span>
<span class="nb">cd</span><span class="w"> </span>/var/lib/dkms/i40e/<span class="si">${</span><span class="nv">DRIVER_VERSION</span><span class="si">}</span>/bmdeb/
dpkg<span class="w"> </span>-c<span class="w"> </span>i40e-modules-<span class="si">${</span><span class="nv">KERNEL_VERSION</span><span class="si">}</span>_*
dpkg<span class="w"> </span>-I<span class="w"> </span>i40e-modules-<span class="si">${</span><span class="nv">KERNEL_VERSION</span><span class="si">}</span>_*
</code></pre></div>

<p>Voici la sortie abrégée des deux dernières commandes :</p>
<div class="language-bash-session codehilite"><pre><span/><code><span class="gp"># </span>dpkg<span class="w"> </span>-c<span class="w"> </span>i40e-modules-<span class="si">${</span><span class="nv">KERNEL_VERSION</span><span class="si">}</span>_*
<span class="go">[…]</span>
<span class="hll"><span class="go">-rw-r--r-- root/root    551664 2018-03-01 19:16 ./lib/modules/4.9.0-6-amd64/updates/dkms/i40e.ko</span>
</span><span class="go">[…]</span>
<span class="gp"># </span>dpkg<span class="w"> </span>-I<span class="w"> </span>i40e-modules-<span class="si">${</span><span class="nv">KERNEL_VERSION</span><span class="si">}</span>_*
<span class="go"> new debian package, version 2.0.</span>
<span class="go">[…]</span>
<span class="go"> Package: i40e-modules-4.9.0-6-amd64</span>
<span class="go"> Source: i40e-dkms-bin</span>
<span class="go"> Version: 2.4.6</span>
<span class="go"> Architecture: amd64</span>
<span class="go"> Installed-Size: 555</span>
<span class="go"> Depends: linux-image-4.9.0-6-amd64</span>
<span class="hll"><span class="go"> Provides: i40e-modules</span>
</span><span class="go"> Section: misc</span>
<span class="go"> Priority: optional</span>
<span class="go"> Description: i40e binary drivers for linux-image-4.9.0-6-amd64</span>
<span class="go">  This package contains i40e drivers for the 4.9.0-6-amd64 Linux kernel,</span>
<span class="go">  built from i40e-dkms for the amd64 architecture.</span>
</code></pre></div>

<p>Le paquet Debian ainsi créé contient le pilote précompilé et ne dépend
que du noyau associé. Vous pouvez l’installer sans tirer des dizaines
de dépendances supplémentaires.</p>
<div class="footnote">
<hr/>
<ol>
<li id="fn:rpm">
<p><em><abbr title="Dynamic Kernel Module Support">DKMS</abbr></em> est également compatible avec les distributions à base
de RPM mais le contenu de cet article ne s’applique pas à
celles-ci. <a class="footnote-backref" href="#fnref:rpm" title="Jump back to footnote 1 in the text">↩</a></p>
</li>
<li id="fn:apt">
<p>Quelques paquets additionels sont nécessaires :
<code>build-essential</code>, <code>fakeroot</code> et <code>debhelper</code>. <a class="footnote-backref" href="#fnref:apt" title="Jump back to footnote 2 in the text">↩</a></p>
</li>
<li id="fn:version">
<p>Disponible pour Debian Stretch ainsi que pour Debian
Jessie, via un rétroportage. Toutefois, la version dans Ubuntu
Xenial est trop ancienne. <a class="footnote-backref" href="#fnref:version" title="Jump back to footnote 3 in the text">↩</a></p>
</li>
</ol>
</div>
      </div>
    </content>
  </entry>
  <entry>
    <title type="html">Vienna Linux Meetup : les distributions sont-elles encore pertinentes ?</title>
    <author><name>Vincent Bernat</name></author>
    <link href="https://vincent.bernat.ch/fr/blog/2017-vienne-distributions-linux" rel="alternate"/>
    <link href="https://vincent.bernat.ch/fr/blog/2017-vienne-distributions-linux#isso-thread" rel="replies" type="text/html"/>
    <updated>2017-11-07T18:00:00Z</updated>
    <id>http://www.luffy.cx/fr/blog/2017-vienne-distributions-linux.html</id>

    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p>Voici les diapositives (en anglais) que j’ai présentées pour une
<a href="https://www.meetup.com/viennalinux/">rencontre Linux à Vienne</a>. Je partage ce que les
distributions apportent depuis plusieurs décennies et j’explique
pourquoi cela est encore en partie nécessaire aujourd’hui, malgré la
banalisation des conteneurs.</p>
<figure class="lf-fullbleed"><div class="lf-media-outer" style="width: 992px"><span class="lf-media-inner" style="padding-bottom: 56.250%"><object width="992" height="558" type="application/pdf" data="https://media.bernat.ch/files/slides-vienna-linux-meetup.pdf#toolbar=0&amp;navpanes=0&amp;scrollbar=0&amp;view=Fit&amp;zoom=page-fit&amp;pagemode=none" class="lf-media lf-opaque"><a href="https://media.bernat.ch/files/slides-vienna-linux-meetup.pdf">Diapositives au format PDF</a></object></span></div></figure>
      </div>
    </content>
  </entry>
  <entry>
    <title type="html">Petit traité empirique de l'empaquetage Debian (2016)</title>
    <author><name>Vincent Bernat</name></author>
    <link href="https://vincent.bernat.ch/fr/blog/2016-empaquetage-debian-empirique" rel="alternate"/>
    <link href="https://vincent.bernat.ch/fr/blog/2016-empaquetage-debian-empirique#isso-thread" rel="replies" type="text/html"/>
    <updated>2016-05-02T17:25:13Z</updated>
    <id>http://www.luffy.cx/fr/blog/2016-empaquetage-debian-empirique.html</id>

    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<div class="admonition">
<p class="admonition-title">Mise à jour (05.2019)</p>
<p>Consultez plutôt la <a href="/fr/blog/2019-empaquetage-debian-empirique">version
2019</a> de ce guide si
vous n’avez besoin de cibler que des distributions récentes (telles que
Debian Stretch et Ubuntu Bionic).</p>
</div>
<p>Bien que la création de paquets Debian soit <a href="https://www.debian.org/doc/manuals/maint-guide/index.fr.html" title="Guide des nouveaux responsables Debian">abondamment</a>
<a href="https://www.debian.org/doc/manuals/maint-guide/index.fr.html" title="Guide des nouveaux responsables Debian">documentée</a>, la plupart des <a href="https://www.debian.org/doc/manuals/packaging-tutorial/packaging-tutorial" title="Lucas Nussbaum's packaging tutorial">tutoriaux</a> ciblent
les paquets respectueux de la <a href="https://www.debian.org/doc/debian-policy/" title="La charte Debian">charte Debian</a>. De plus, leur
création a longtemps eu la <strong>réputation d’être particulièrement
difficile</strong><sup id="fnref:difficulty"><a class="footnote-ref" href="#fn:difficulty">1</a></sup> et beaucoup se sont tournés vers des outils
moins contraignants<sup id="fnref:fpm"><a class="footnote-ref" href="#fn:fpm">2</a></sup> tels que <a href="https://github.com/jordansissel/fpm" title="Effing package management">fpm</a> ou <a href="https://web.archive.org/web/2016/http://checkinstall.izto.org/" title="CheckInstall">CheckInstall</a>.</p>
<p>Toutefois, la construction de paquets Debian en utilisant les outils
officiels est plutôt simple en appliquant ces quelques concessions :</p>
<ol>
<li>
<p><strong>Aucun paquet source ne sera généré</strong>. Les paquets seront
    construits directement depuis une copie propre issue du système de
    versions.</p>
</li>
<li>
<p><strong>Des dépendances supplémentaires peuvent être téléchargées
    pendant la construction</strong>. Empaqueter individuellement chaque
    dépendance est un travail ingrat, notamment avec certains
    environnements tels que Java, JavaScript et Go.</p>
</li>
<li>
<p>Les paquets produits peuvent <strong>combiner et inclure des dépendances
    tierces</strong>. Cela peut lever certaines objections liées à la
    sécurité et à la maintenance à long terme, mais c’est une
    concession courante dans certains écosystèmes tels que Java,
    JavaScript et Go.</p>
</li>
</ol>
<div class="toc">
<ul>
<li><a href="#ceinture-blanche">Ceinture blanche</a><ul>
<li><a href="#le-fichier-de-controle">Le fichier de contrôle</a></li>
<li><a href="#la-recette">La recette</a></li>
</ul>
</li>
<li><a href="#ceinture-jaune">Ceinture jaune</a><ul>
<li><a href="#les-dependances-sources">Les dépendances sources</a></li>
<li><a href="#les-dependances-binaires">Les dépendances binaires</a></li>
<li><a href="#integration-avec-un-systeme-de-demarrage">Intégration avec un système de démarrage</a><ul>
<li><a href="#system-v">System-V</a></li>
<li><a href="#upstart">Upstart</a></li>
<li><a href="#systemd">systemd</a></li>
</ul>
</li>
<li><a href="#utilisateur-dedie">Utilisateur dédié</a></li>
</ul>
</li>
<li><a href="#ceinture-verte">Ceinture verte</a><ul>
<li><a href="#banalites">Banalités</a></li>
<li><a href="#construction-automatique">Construction automatique</a></li>
<li><a href="#fichiers-supplementaires">Fichiers supplémentaires</a></li>
</ul>
</li>
<li><a href="#autres-exemples">Autres exemples</a></li>
</ul>
</div>
<h1 id="ceinture-blanche">Ceinture blanche</h1>
<p>Deux types de paquets coexistent dans l’archive Debian : les <strong>paquets
sources</strong> et les <strong>paquets binaires</strong>. Un paquet source produit un ou
plusieurs paquets binaires. Chaque paquet doit porter un nom.</p>
<p>Comme indiqué lors de l’introduction, aucun paquet source ne sera
construit. Nous allons travailler directement sur sa représentation
décompressée : une arborescence de fichiers incluant le répertoire
<code>debian/</code>. Les exemples qui suivent utilisent une arborescence
composée uniquement du répertoire <code>debian/</code>, mais ce dernier peut être
inclus dans n’importe quel project existant.</p>
<p>Comme point de départ, nous allons empaqueter <a href="https://memcached.org/" title="memcached - a distributed memory object caching system">memcached</a>, un cache
mémoire distribué. Il nous faut créer quatre fichiers :</p>
<ul>
<li><code>debian/compat</code>,</li>
<li><code>debian/changelog</code>,</li>
<li><code>debian/control</code> et</li>
<li><code>debian/rules</code>.</li>
</ul>
<p>Le premier contient uniquement <code>9</code><sup id="fnref:compat"><a class="footnote-ref" href="#fn:compat">3</a></sup> :</p>
<div class="language-bash codehilite"><pre><span/><code><span class="nb">echo</span><span class="w"> </span><span class="m">9</span><span class="w"> </span>&gt;<span class="w"> </span>debian/compat
</code></pre></div>

<p>Le second contient ceci :</p>
<div class="language-text-only codehilite"><pre><span/><code>memcached (0.0-0) UNRELEASED; urgency=medium

  * Fake entry

 -- Happy Packager &lt;happy@example.com&gt;  Tue, 19 Apr 2016 22:27:05 +0200
</code></pre></div>

<p>La seule information d’importance est le nom du paquet source,
<code>memcached</code>, sur la première ligne. Toutes les autres informations
sont sans influence sur les paquets créés.</p>
<h2 id="le-fichier-de-controle">Le fichier de contrôle</h2>
<p><code>debian/control</code> décrit les méta-données à propos du paquet source et
des paquets binaires. Un bloc est dédié à chacun d’eux.</p>
<div class="language-debian-control-file codehilite"><pre><span/><code><span class="k">Source</span><span class="p">:</span><span class="w"> </span><span class="s">memcached</span>
<span class="k">Maintainer</span><span class="p">:</span><span class="w"> </span>Vincent Bernat <span class="gs">&lt;bernat@debian.org&gt;</span>

<span class="k">Package</span><span class="p">:</span><span class="w"> </span><span class="s">memcached</span>
<span class="k">Architecture</span><span class="p">:</span><span class="w"> </span><span class="s">any</span>
<span class="k">Description</span><span class="gs">: high-performance memory object caching system</span>
</code></pre></div>

<p>Le paquet source est <code>memcached</code>. Il faut utiliser le même nom que
dans le fichier <code>debian/changelog</code>.</p>
<p>Un seul paquet binaire est créé : <code>memcached</code>. Par la suite, si vous
voyez <code>memcached</code>, il s’agit du nom du paquet binaire. Le champ
<code>Architecture</code> doit être soit <code>any</code>, soit <code>all</code>. Ce dernier est
utilisé exclusivement si tous les fichiers sont indépendants de
l’architecture matérielle. Dans le doute, il suffit de mettre <code>any</code>.</p>
<p>Le champ <code>Description</code> contient une courte description du paquet
binaire.</p>
<h2 id="la-recette">La recette</h2>
<p>Le dernier fichier à rédiger est <code>debian/rules</code>. Il s’agit de la
recette du paquet. Nous avons besoin de télécharger <em>memcached</em>, le
construire et installer son arborescence dans <code>debian/memcached/</code> :</p>
<div class="language-makefile codehilite"><pre><span/><code><span class="c">#!/usr/bin/make -f</span>

<span class="nv">DISTRIBUTION</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">$(</span>shell<span class="w"> </span>lsb_release<span class="w"> </span>-sr<span class="k">)</span>
<span class="nv">VERSION</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span>.4.25
<span class="nv">PACKAGEVERSION</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">$(</span>VERSION<span class="k">)</span>-0~<span class="k">$(</span>DISTRIBUTION<span class="k">)</span><span class="m">0</span>
<span class="nv">TARBALL</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>memcached-<span class="k">$(</span>VERSION<span class="k">)</span>.tar.gz
<span class="nv">URL</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>http://www.memcached.org/files/<span class="k">$(</span>TARBALL<span class="k">)</span>

<span class="nf">%</span><span class="o">:</span>
<span class="w">    </span>dh<span class="w"> </span><span class="nv">$@</span>

<span class="nf">override_dh_auto_clean</span><span class="o">:</span>
<span class="nf">override_dh_auto_test</span><span class="o">:</span>
<span class="nf">override_dh_auto_build</span><span class="o">:</span>
<span class="nf">override_dh_auto_install</span><span class="o">:</span>
<span class="w">    </span>wget<span class="w"> </span>-N<span class="w"> </span>--progress<span class="o">=</span>dot:mega<span class="w"> </span><span class="k">$(</span>URL<span class="k">)</span>
<span class="w">    </span>tar<span class="w"> </span>--strip-components<span class="o">=</span><span class="m">1</span><span class="w"> </span>-xf<span class="w"> </span><span class="k">$(</span>TARBALL<span class="k">)</span>
<span class="w">    </span>./configure<span class="w"> </span>--prefix<span class="o">=</span>/usr
<span class="w">    </span>make
<span class="w">    </span>make<span class="w"> </span>install<span class="w"> </span><span class="nv">DESTDIR</span><span class="o">=</span>debian/memcached

<span class="nf">override_dh_gencontrol</span><span class="o">:</span>
<span class="w">    </span>dh_gencontrol<span class="w"> </span>--<span class="w"> </span>-v<span class="k">$(</span>PACKAGEVERSION<span class="k">)</span>
</code></pre></div>

<p>Les cibles vides <code>override_dh_auto_clean</code>, <code>override_dh_auto_test</code> et
<code>override_dh_auto_build</code> permettent de s’assurer que <em>debhelper</em> ne
fera rien de « magique ». La cible <code>override_dh_gencontrol</code> permet de
spécifier la version<sup id="fnref:version"><a class="footnote-ref" href="#fn:version">4</a></sup> sans avoir à tenir à jour
<code>debian/changelog</code>. Cette recette est très similaire à ce qui aurait
été écrit pour <code>fpm</code> :</p>
<div class="language-bash codehilite"><pre><span/><code><span class="nv">DISTRIBUTION</span><span class="o">=</span><span class="k">$(</span>lsb_release<span class="w"> </span>-sr<span class="k">)</span>
<span class="nv">VERSION</span><span class="o">=</span><span class="m">1</span>.4.25
<span class="nv">PACKAGEVERSION</span><span class="o">=</span><span class="si">${</span><span class="nv">VERSION</span><span class="si">}</span>-0~<span class="si">${</span><span class="nv">DISTRIBUTION</span><span class="si">}</span><span class="m">0</span>
<span class="nv">TARBALL</span><span class="o">=</span>memcached-<span class="si">${</span><span class="nv">VERSION</span><span class="si">}</span>.tar.gz
<span class="nv">URL</span><span class="o">=</span>http://www.memcached.org/files/<span class="si">${</span><span class="nv">TARBALL</span><span class="si">}</span>

wget<span class="w"> </span>-N<span class="w"> </span>--progress<span class="o">=</span>dot:mega<span class="w"> </span><span class="si">${</span><span class="nv">URL</span><span class="si">}</span>
tar<span class="w"> </span>--strip-components<span class="o">=</span><span class="m">1</span><span class="w"> </span>-xf<span class="w"> </span><span class="si">${</span><span class="nv">TARBALL</span><span class="si">}</span>
./configure<span class="w"> </span>--prefix<span class="o">=</span>/usr
make
make<span class="w"> </span>install<span class="w"> </span><span class="nv">DESTDIR</span><span class="o">=</span>/tmp/installdir

<span class="c1"># Build the final package</span>
fpm<span class="w"> </span>-s<span class="w"> </span>dir<span class="w"> </span>-t<span class="w"> </span>deb<span class="w"> </span><span class="se">\</span>
<span class="w">    </span>-n<span class="w"> </span>memcached<span class="w"> </span><span class="se">\</span>
<span class="w">    </span>-v<span class="w"> </span><span class="si">${</span><span class="nv">PACKAGEVERSION</span><span class="si">}</span><span class="w"> </span><span class="se">\</span>
<span class="w">    </span>-C<span class="w"> </span>/tmp/installdir<span class="w"> </span><span class="se">\</span>
<span class="w">    </span>--description<span class="w"> </span><span class="s2">"high-performance memory object caching system"</span>
</code></pre></div>

<p>Vous pouvez lire le résultat final sur <a href="https://github.com/vincentbernat/pragmatic-debian-packages/tree/2016/memcached-basic/debian">GitHub</a> et
le construire avec la commande <code>dpkg-buildpackage -us -uc -b</code>.</p>
<h1 id="ceinture-jaune">Ceinture jaune</h1>
<p>À partir de là, il est possible d’inclure quelques
améliorations. <strong>Aucune n’est essentielle</strong> mais le gain est
suffisamment intéressant pour justifier l’effort.</p>
<h2 id="les-dependances-sources">Les dépendances sources</h2>
<p>Notre recette initiale ne fonctionne que si nous disposons déjà de
<code>wget</code> et de <code>libevent-dev</code>. Ces paquets ne sont pas présents sur tous
les systèmes. Il est assez aisé de spécifier ces dépendances en
ajoutant un champ <code>Build-Depends</code> dans <code>debian/control</code> :</p>
<div class="language-debian-control-file codehilite"><pre><span/><code><span class="k">Source</span><span class="p">:</span><span class="w"> </span><span class="s">memcached</span>
<span class="k">Build-Depends</span><span class="p">:</span><span class="w"> </span><span class="nf">debhelper</span> <span class="p">(</span><span class="o">&gt;=</span><span class="w"> </span><span class="m">9</span><span class="p">)</span>,
<span class="w"> </span>              <span class="nf">wget</span>, <span class="nf">ca-certificates</span>, <span class="nf">lsb-release</span>,
<span class="w"> </span>              <span class="nf">libevent-dev</span>
</code></pre></div>

<p>Il faut toujours spécifier <code>debhelper (&gt;= 9)</code> car son utilisation est
centrale dans <code>debian/rules</code>. Il n’y a pas besoin de dépendre de
<code>make</code> ou d’un compilateur C car le paquet <code>build-essential</code> est
considéré comme toujours présent et il les fournit
indirectement. <code>dpkg-buildpackage</code> se plaindra si une des dépendances
est manquante. Pour installer sans peine ces paquets, vous pouvez
utiliser la commande suivante<sup id="fnref:devscripts"><a class="footnote-ref" href="#fn:devscripts">5</a></sup> :</p>
<div class="language-bash codehilite"><pre><span/><code>mk-build-deps<span class="w"> </span><span class="se">\</span>
<span class="w">    </span>-t<span class="w"> </span><span class="s1">'apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends -qqy'</span><span class="w"> </span><span class="se">\</span>
<span class="w">    </span>-i<span class="w"> </span>-r<span class="w"> </span>debian/control
</code></pre></div>

<p>Il est aussi intéressant de se pencher sur des outils tels que
<a href="https://pbuilder-team.pages.debian.net/pbuilder/" title="pbuilder user's manual">pbuilder</a> et <a href="https://wiki.debian.org/sbuild" title="sbuild page on Debian Wiki">sbuild</a> qui permettent de construire des paquets
dans un environnement minimal et isolé.</p>
<h2 id="les-dependances-binaires">Les dépendances binaires</h2>
<p>Si le paquet ainsi construit est installé sur une machine vierge,
<em>memcached</em> refusera de démarrer en raison de l’absence de
<em>libevent</em>. Il est possible d’exprimer cette dépendance en ajoutant un
champ <code>Depends</code> dans le fichier <code>debian/control</code>. De plus, dans le cas
des bibliothèques dynamiques, ces dépendances peuvent être générées
automatiquement en utilisant des variables de substitution :</p>
<div class="language-debian-control-file codehilite"><pre><span/><code><span class="k">Package</span><span class="p">:</span><span class="w"> </span><span class="s">memcached</span>
<span class="k">Depends</span><span class="p">:</span><span class="w"> </span><span class="o">$</span><span class="p">{</span><span class="ni">misc</span><span class="p">:</span>Depends<span class="p">}</span>, <span class="o">$</span><span class="p">{</span><span class="ni">shlibs</span><span class="p">:</span>Depends<span class="p">}</span>
</code></pre></div>

<p>Le paquet construit contiendra les informations suivantes :</p>
<div class="language-bash-session codehilite"><pre><span/><code><span class="gp">$ </span>dpkg<span class="w"> </span>-I<span class="w"> </span>../memcached_1.4.25-0<span class="se">\~</span>unstable0_amd64.deb<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>Depends
<span class="go"> Depends: libc6 (&gt;= 2.17), libevent-2.0-5 (&gt;= 2.0.10-stable)</span>
</code></pre></div>

<h2 id="integration-avec-un-systeme-de-demarrage">Intégration avec un système de démarrage</h2>
<p>La plupart des paquets fournissant un démon incluent une intégration
avec le système de démarrage afin de démarrer le démon au boot ou de
le redémarrer après une mise à jour. Pour les distributions basées sur
Debian, il existe plusieurs systèmes de démarrage. Voici les trois
plus courants.</p>
<ul>
<li><strong>System-V</strong> est le système historique. Ces scripts de démarrage
   peuvent être réutilisés par les autres systèmes. Il s’agit donc du
   plus petit dénominateur commun.</li>
<li><strong>Upstart</strong> est le système popularisé par Ubuntu. Il est utilisé
   jusqu’à la version 14.10, incluse.</li>
<li><strong>systemd</strong> est le système par défaut pour Debian depuis Jessie et
   pour Ubuntu depuis la version 15.04.</li>
</ul>
<p>Écrire un script de démarrage pour <em>System-V</em> est une tâche
ardue. Habituellement, je préfère donc simplement fournir un script
pour le système de démarrage par défaut de la distribution visée
(<em>Upstart</em> et <em>systemd</em>).</p>
<h3 id="system-v">System-V</h3>
<p>Si vous voulez écrire un script de démarrage pour <em>System-V</em>,
adaptez<sup id="fnref:provided"><a class="footnote-ref" href="#fn:provided">6</a></sup> le script <code>/etc/init.d/skeleton</code> de la distribution
la plus ancienne que vous souhaitez supporter. Mettez le résultat dans
le fichier <code>debian/memcached.init</code>. Il sera installé au bon endroit et
invoqué lors de l’installation, mise à jour ou retrait du
paquet. Habituellement, l’utilisateur peut personnaliser les options
du démon en modifiant le fichier <code>/etc/default/memcached</code>. Pour en
fournir un, placez son contenu dans le fichier <code>debian/memcached.default</code>.</p>
<h3 id="upstart">Upstart</h3>
<p>Fournir un script pour <em>Upstart</em> est similaire : son contenu doit être
placé dans <code>debian/memcached.upstart</code>. Par exemple :</p>
<div class="language-text-only codehilite"><pre><span/><code>description "memcached daemon"

start on runlevel [2345]
stop on runlevel [!2345]
respawn
respawn limit 5 60
expect daemon

script
  . /etc/default/memcached
  exec memcached -d -u $USER -p $PORT -m $CACHESIZE -c $MAXCONN $OPTIONS
end script
</code></pre></div>

<p>La directive la plus importante à surveiller est <a href="https://web.archive.org/web/2013/http://upstart.ubuntu.com/cookbook/#expect" title="Upstart cookbook: expect stanza">expect</a>. Ici, nous
utilisons <code>expect daemon</code> et <em>memcached</em> est démarré avec l’option
<code>-d</code>.</p>
<h3 id="systemd">systemd</h3>
<p>Fournir un script pour <em>systemd</em> est un tout petit peu plus
compliqué. Le contenu doit se placer dans
<code>debian/memcached.service</code>. Par exemple :</p>
<div class="language-systemd codehilite"><pre><span/><code><span class="k">[Unit]</span>
<span class="na">Description</span><span class="o">=</span><span class="s">memcached daemon</span>
<span class="na">After</span><span class="o">=</span><span class="s">network.target</span>

<span class="k">[Service]</span>
<span class="na">Type</span><span class="o">=</span><span class="s">forking</span>
<span class="na">EnvironmentFile</span><span class="o">=</span><span class="s">/etc/default/memcached</span>
<span class="na">ExecStart</span><span class="o">=</span><span class="s">/usr/bin/memcached -d -u $USER -p $PORT -m $CACHESIZE -c $MAXCONN $OPTIONS</span>
<span class="na">Restart</span><span class="o">=</span><span class="s">on-failure</span>

<span class="k">[Install]</span>
<span class="na">WantedBy</span><span class="o">=</span><span class="s">multi-user.target</span>
</code></pre></div>

<p>Bien que cela ne soit pas considéré comme une bonne
pratique<sup id="fnref:default"><a class="footnote-ref" href="#fn:default">7</a></sup>, nous réutilisons <code>/etc/default/memcached</code>. Comme
pour <em>Upstart</em>, la directive <code>Type</code> est particulièrement
importante. Nous utilisons <code>forking</code> car <em>memcached</em> est démarré avec
l’option <code>-d</code>.</p>
<div class="admonition">
<p class="admonition-title">Mise à jour (11.2017)</p>
<p>Pour les paquets destinés à Debian Stretch ou Ubuntu Yaketty (ou plus
récents), placez <code>10</code> dans le fichier <code>debian/compat</code> et ignorez les
instructions suivantes.</p>
</div>
<p>Il est également nécessaire d’ajouter une dépendance source sur
<code>dh-systemd</code> dans <code>debian/control</code> :</p>
<div class="language-debian-control-file codehilite"><pre><span/><code><span class="k">Source</span><span class="p">:</span><span class="w"> </span><span class="s">memcached</span>
<span class="k">Build-Depends</span><span class="p">:</span><span class="w"> </span><span class="nf">debhelper</span> <span class="p">(</span><span class="o">&gt;=</span><span class="w"> </span><span class="m">9</span><span class="p">)</span>,
<span class="w"> </span>              <span class="nf">wget</span>, <span class="nf">ca-certificates</span>, <span class="nf">lsb-release</span>,
<span class="w"> </span>              <span class="nf">libevent-dev</span>,
<span class="w"> </span>              <span class="nf">dh-systemd</span>
</code></pre></div>

<p>Il faut également modifier la règle par défaut dans <code>debian/rules</code> :</p>
<div class="language-makefile codehilite"><pre><span/><code><span class="nf">%</span><span class="o">:</span>
<span class="w">    </span>dh<span class="w"> </span><span class="nv">$@</span><span class="w"> </span>--with<span class="w"> </span>systemd
</code></pre></div>

<p>Cette complexité supplémentaire est regrettable et est due au fait que
l’intégration de <em>systemd</em> ne faisait pas partie de
<em>debhelper</em><sup id="fnref:bug822670"><a class="footnote-ref" href="#fn:bug822670">8</a></sup>. Sans ces modifications, le script sera
installé mais l’intégration n’aura pas lieu et il ne sera pas lancé au
démarrage de la machine.</p>
<h2 id="utilisateur-dedie">Utilisateur dédié</h2>
<p>De nombreux démons n’ont pas besoin de s’exécuter en tant que <em>root</em>
et c’est souvent une bonne idée de fournir un utilisateur dédié. Dans
le cas de <em>memcached</em>, nous allons fournir l’utilisateur
<code>_memcached</code><sup id="fnref:naming"><a class="footnote-ref" href="#fn:naming">9</a></sup>.</p>
<div class="admonition">
<p class="admonition-title">Mise à jour (11.2018)</p>
<p>Si vous utilisez exclusivement <em>systemd</em>, il est possible d’économiser du
temps et de l’énergie en exploitant plutôt sa <a href="http://0pointer.net/blog/dynamic-users-with-systemd.html" title="Dynamic Users with systemd">gestion des utilisateurs
dynamiques</a>.</p>
</div>
<p>Ajoutez un fichier <code>debian/memcached.postinst</code> avec le contenu
suivant :</p>
<div class="language-bash codehilite"><pre><span/><code><span class="ch">#!/bin/sh</span>

<span class="nb">set</span><span class="w"> </span>-e

<span class="k">case</span><span class="w"> </span><span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span><span class="w"> </span><span class="k">in</span>
<span class="w">    </span>configure<span class="o">)</span>
<span class="w">        </span>adduser<span class="w"> </span>--system<span class="w"> </span>--disabled-password<span class="w"> </span>--disabled-login<span class="w"> </span>--home<span class="w"> </span>/var/empty<span class="w"> </span><span class="se">\</span>
<span class="w">                </span>--no-create-home<span class="w"> </span>--quiet<span class="w"> </span>--force-badname<span class="w"> </span>--group<span class="w"> </span>_memcached
<span class="w">        </span><span class="p">;;</span>
<span class="k">esac</span>

<span class="c1">#DEBHELPER#</span>

<span class="nb">exit</span><span class="w"> </span><span class="m">0</span>
</code></pre></div>

<p>Lorsque le paquet est désinstallé, aucun ménage n’est effectué :</p>
<ul>
<li>moins de code à écrire, moins de bugs ;</li>
<li>l’utilisateur peut toujours posséder quelques fichiers sur le système.</li>
</ul>
<p>L’utilitaire <code>adduser</code> effectuera toujours la bonne action que
l’utilisateur demandé existe déjà ou non. Il faut penser à l’ajouter
comme dépendance binaire dans <code>debian/control</code> :</p>
<div class="language-debian-control-file codehilite"><pre><span/><code><span class="k">Package</span><span class="p">:</span><span class="w"> </span><span class="s">memcached</span>
<span class="k">Depends</span><span class="p">:</span><span class="w"> </span><span class="o">$</span><span class="p">{</span><span class="ni">misc</span><span class="p">:</span>Depends<span class="p">}</span>, <span class="o">$</span><span class="p">{</span><span class="ni">shlibs</span><span class="p">:</span>Depends<span class="p">}</span>, <span class="nf">adduser</span>
</code></pre></div>

<p>Le marqueur <code>#DEBHELPER#</code> indique le point d’insertion pour des
scripts d’intégration supplémentaires.</p>
<p>Le résultat final est disponible sur
<a href="https://github.com/vincentbernat/pragmatic-debian-packages/tree/2016/memcached-intermediate/debian">GitHub</a> et peut être testé avec la
commande <code>dpkg-buildpackage -us -uc -b</code>.</p>
<h1 id="ceinture-verte">Ceinture verte</h1>
<p>Il est possible d’exploiter certaines capacités de <em>debhelper</em> pour
<strong>réduire la taille</strong> du fichier <code>debian/rules</code> et pour le rendre
<strong>plus déclaratif</strong>. Cette section est totalement optionnelle : vous
pouvez la sauter si besoin.</p>
<h2 id="banalites">Banalités</h2>
<p>Il y a <strong>quatre étapes</strong> dans la construction d’un paquet Debian :</p>
<ol>
<li>
<p><code>debian/rules clean</code> va <strong>nettoyer</strong> l’arborescence pour revenir
    dans son état initial.</p>
</li>
<li>
<p><code>debian/rules build</code> doit <strong>construire</strong> le logiciel. Pour quelque
    chose de basé sur <em>autoconf</em>, comme <em>memcached</em>, il s’agit
    essentiellement d’exécuter <code>./configure &amp;&amp; make</code>.</p>
</li>
<li>
<p><code>debian/rules install</code> doit <strong>installer</strong> l’arborescence de chaque
    paquet binaire dans le répertoire approprié. Pour des logiciels
    basés sur <em>autoconf</em>, il s’agit d’exécuter <code>make install
    DESTDIR=debian/memcached</code>.</p>
</li>
<li>
<p><code>debian/rules binary</code> doit <strong>empaqueter</strong> les différentes
    arborescences en paquets binaires.</p>
</li>
</ol>
<p>Il ne faut pas écrire directement chacune de ces cibles. L’utilitaire
<code>dh</code>, un composant de <em>debhelper</em>, va faire la majeure partie du
boulot. Le fichier <code>debian/rules</code> minimaliste suivant suffit pour accomplir
cette tâche pour de nombreux paquets sources :</p>
<div class="language-makefile codehilite"><pre><span/><code><span class="c">#!/usr/bin/make -f</span>
<span class="nf">%</span><span class="o">:</span>
<span class="w">    </span>dh<span class="w"> </span><span class="nv">$@</span>
</code></pre></div>

<p>Pour chacune des quatre cibles décrites ci-dessus, vous pouvez
exécuter <code>dh --no-act</code> pour voir les utilitaires invoqués. Par
exemple :</p>
<div class="language-bash-session codehilite"><pre><span/><code><span class="gp">$ </span>dh<span class="w"> </span>build<span class="w"> </span>--no-act
<span class="go">   dh_testdir</span>
<span class="go">   dh_update_autotools_config</span>
<span class="go">   dh_auto_configure</span>
<span class="go">   dh_auto_build</span>
<span class="go">   dh_auto_test</span>
</code></pre></div>

<p>Chacun de ces utilitaires dispose d’une page de manuel. Ceux
commençant par <code>dh_auto</code> sont un peu « magiques ». Par exemple,
<code>dh_auto_configure</code> va tenter de configurer automatiquement le
logiciel avant l’étape de construction. Selon les cas, il peut
invoquer <code>./configure</code>, <code>cmake</code> ou <code>Makefile.PL</code>.</p>
<p>Si un des utilitaires <code>dh_</code> ne fait pas ce qu’il faut, il est possible
de le remplacer en déclarant une cible nommée de manière adéquate :</p>
<div class="language-makefile codehilite"><pre><span/><code><span class="nf">override_dh_auto_configure</span><span class="o">:</span>
<span class="w">    </span>./configure<span class="w"> </span>--with-some-grog
</code></pre></div>

<p>Chaque utilitaire est également configurable via des options. Ainsi,
il est possible de modifier leurs comportements en définissant la cible
correspondante et en invoquant l’utilitaire manuellement :</p>
<div class="language-makefile codehilite"><pre><span/><code><span class="nf">override_dh_auto_configure</span><span class="o">:</span>
<span class="w">    </span>dh_auto_configure<span class="w"> </span>--<span class="w"> </span>--with-some-grog
</code></pre></div>

<p>Ainsi, <code>./configure</code> sera appelé avec l’option <code>--with-some-grog</code> mais
aussi avec des options par défaut telles que <code>--prefix=/usr</code>.</p>
<p>Dans l’exemple initial de <em>memcached</em>, ces cibles « magiques » sont
surchargées. <code>dh_auto_clean</code>, <code>dh_auto_configure</code> et <code>dh_auto_build</code>
ont été neutralisées pour éviter tout comportement
inattendu. <code>dh_auto_install</code> a été détournée pour exécuter l’intégralité
de la construction de l’arborescence cible. De plus, le comportement
de <code>dh_gencontrol</code> a été modifié en lui fournissant le numéro de version
désiré plutôt que de le laisser regarder dans <code>debian/changelog</code>.</p>
<h2 id="construction-automatique">Construction automatique</h2>
<p><em>memcached</em> utilisant <em>autoconf</em>, <code>dh</code> <strong>sait comment le construire</strong> :
<code>./configure &amp;&amp; make &amp;&amp; make install</code>. Il est donc possible de laisser
<code>dh</code> faire la majeure partie du boulot avec le fichier debian/rules
suivant :</p>
<div class="language-makefile codehilite"><pre><span/><code><span class="c">#!/usr/bin/make -f</span>

<span class="nv">DISTRIBUTION</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">$(</span>shell<span class="w"> </span>lsb_release<span class="w"> </span>-sr<span class="k">)</span>
<span class="nv">VERSION</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span>.4.25
<span class="nv">PACKAGEVERSION</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">$(</span>VERSION<span class="k">)</span>-0~<span class="k">$(</span>DISTRIBUTION<span class="k">)</span><span class="m">0</span>
<span class="nv">TARBALL</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>memcached-<span class="k">$(</span>VERSION<span class="k">)</span>.tar.gz
<span class="nv">URL</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>http://www.memcached.org/files/<span class="k">$(</span>TARBALL<span class="k">)</span>

<span class="nf">%</span><span class="o">:</span>
<span class="w">    </span>dh<span class="w"> </span><span class="nv">$@</span><span class="w"> </span>--with<span class="w"> </span>systemd

<span class="nf">override_dh_auto_clean</span><span class="o">:</span>
<span class="w">    </span>wget<span class="w"> </span>-N<span class="w"> </span>--progress<span class="o">=</span>dot:mega<span class="w"> </span><span class="k">$(</span>URL<span class="k">)</span>
<span class="w">    </span>tar<span class="w"> </span>--strip-components<span class="o">=</span><span class="m">1</span><span class="w"> </span>-xf<span class="w"> </span><span class="k">$(</span>TARBALL<span class="k">)</span>

<span class="nf">override_dh_auto_test</span><span class="o">:</span>
<span class="c">    # Don't run the whitespace test</span>
<span class="w">    </span>rm<span class="w"> </span>t/whitespace.t
<span class="w">    </span>dh_auto_test

<span class="nf">override_dh_gencontrol</span><span class="o">:</span>
<span class="w">    </span>dh_gencontrol<span class="w"> </span>--<span class="w"> </span>-v<span class="k">$(</span>PACKAGEVERSION<span class="k">)</span>
</code></pre></div>

<p>La cible <code>dh_auto_clean</code> est détournée pour effectuer le
téléchargement et la mise en place de l’arborescence<sup id="fnref:clean"><a class="footnote-ref" href="#fn:clean">10</a></sup>. Ni
<code>dh_auto_configure</code>, ni <code>dh_auto_build</code> ne sont modifiés. <code>dh</code>
appellera <code>./configure</code> avec les options appropriées puis
<code>make</code>. <code>dh_auto_test</code> doit exécuter la suite de tests de
<em>memcached</em>. Toutefois, un des tests échoue en raison d’un
fichier dans le répertoire <code>debian/</code>. Nous supprimons ce test
récalcitrant et invoquons manuellement
<code>dh_auto_test</code>. <code>dh_auto_install</code> n’est pas surchargé et <code>dh</code>
exécutera alors une variante de <code>make install</code>.</p>
<p>Afin de mieux apprécier la différence, la voici sous forme de patch :</p>
<div class="language-diff codehilite"><pre><span/><code><span class="gd">--- memcached-intermediate/debian/rules 2016-04-30 14:02:37.425593362 +0200</span>
<span class="gi">+++ memcached/debian/rules  2016-05-01 14:55:15.815063835 +0200</span>
<span class="gu">@@ -12,10 +12,9 @@</span>
<span class="w"> </span>override_dh_auto_clean:
<span class="gd">-override_dh_auto_test:</span>
<span class="gd">-override_dh_auto_build:</span>
<span class="gd">-override_dh_auto_install:</span>
<span class="w"> </span>   wget -N --progress=dot:mega $(URL)
<span class="w"> </span>   tar --strip-components=1 -xf $(TARBALL)
<span class="gd">-   ./configure --prefix=/usr</span>
<span class="gd">-   make</span>
<span class="gd">-   make install DESTDIR=debian/memcached</span>
<span class="gi">+</span>
<span class="gi">+override_dh_auto_test:</span>
<span class="gi">+   # Don't run the whitespace test</span>
<span class="gi">+   rm t/whitespace.t</span>
<span class="gi">+   dh_auto_test</span>
</code></pre></div>

<p>Vous avez le choix de laisser <code>dh</code> faire une partie du travail ou
non. Il est généralement possible de partir d’un <code>debian/rules</code>
minimal et de surcharger uniquement quelques cibles.</p>
<h2 id="fichiers-supplementaires">Fichiers supplémentaires</h2>
<p>Bien que <code>make install</code> ait installé les fichiers essentiels pour
<em>memcached</em>, il est parfois nécessaire de copier quelques fichiers
supplémentaires dans le paquet binaire. Pour se faire, il est possible
d’utiliser <code>cp</code> ou encore de déclarer les fichiers à copier :</p>
<ul>
<li>les fichiers listés dans <code>debian/memcached.docs</code> seront copiés dans
   <code>/usr/share/doc/memcached</code> par <code>dh_installdocs</code> ;</li>
<li>les fichiers listés dans <code>debian/memcached.examples</code> seront copiés dans
   <code>/usr/share/doc/memcached/examples</code> par <code>dh_installexamples</code> ;</li>
<li>les fichiers listés dans <code>debian/memcached.manpages</code> seront copiés
   dans le sous-répertoire approprié de <code>/usr/share/man</code> par
   <code>dh_installman</code>.</li>
</ul>
<p>Voici un exemple pour <code>debian/memcached.docs</code> :</p>
<div class="language-text-only codehilite"><pre><span/><code>doc/*.txt
</code></pre></div>

<p>Si vous avez besoin de copier des fichiers à un endroit arbitraire, il
est possible de lister ceux-ci ainsi que leur répertoire cible dans le
fichier <code>debian/memcached.install</code>. <code>dh_install</code> se chargera de la
copie. Par exemple :</p>
<div class="language-text-only codehilite"><pre><span/><code>scripts/memcached-tool usr/bin
</code></pre></div>

<p>L’utilisation de ces fichiers permet une description <strong>plus
déclarative</strong> de la recette. Il s’agit d’une histoire de goût et vous
pouvez tout à fait utiliser <code>cp</code> à la place. Le résultat final est
visible sur <a href="https://github.com/vincentbernat/pragmatic-debian-packages/tree/2016/memcached/debian">GitHub</a>.</p>
<h1 id="autres-exemples">Autres exemples</h1>
<p>Le <a href="https://github.com/vincentbernat/pragmatic-debian-packages/tree/2016" title="Dépôt Git rempli de paquets Debian simples à comprendre">dépôt Git</a> comprend d’autres exemples. Ils suivent tous
le même schéma et mettent en œuvre les techniques décrites dans les
sections précédentes.</p>
<p>Il y a notamment des exemples de démons en <a href="https://github.com/vincentbernat/pragmatic-debian-packages/tree/2016/riemann/debian">Java</a>, <a href="https://github.com/vincentbernat/pragmatic-debian-packages/tree/2016/etcd/debian">Go</a>,
<a href="https://github.com/vincentbernat/pragmatic-debian-packages/tree/2016/puppetboard/debian">Python</a> et <a href="https://github.com/vincentbernat/pragmatic-debian-packages/tree/2016/kiwiirc/debian">Node.js</a>. Le but de ces exemples est de démontrer que
l’utilisation des outils Debian est relativement simple. Mission accomplie ?</p>
<div class="footnote">
<hr/>
<ol>
<li id="fn:difficulty">
<p>La mémoire collective est toujours marquée par la
glorieuse époque précédant l’introduction de
<em>debhelper</em> 7.0.50 (circa 2009). La création du fichier
<code>debian/rules</code> était alors particulièrement
laborieuse. Toutefois, de nos jours, le squelette est
devenu minimal. <a class="footnote-backref" href="#fnref:difficulty" title="Jump back to footnote 1 in the text">↩</a></p>
</li>
<li id="fn:fpm">
<p>La complexité n’est pas la seule raison de ce choix : les
outils alternatifs proposent également la création de paquets
RPM, ce que les outils Debian ne permettent pas. <a class="footnote-backref" href="#fnref:fpm" title="Jump back to footnote 2 in the text">↩</a></p>
</li>
<li id="fn:compat">
<p>Ce niveau de compatibilité est disponible à partir de
Debian 8 et d’Ubuntu Precise. Il couvre donc un large éventail de
distributions. <a class="footnote-backref" href="#fnref:compat" title="Jump back to footnote 3 in the text">↩</a></p>
</li>
<li id="fn:version">
<p>Il y a différentes façons de numéroter les versions d’un
paquet. La façon proposée ici n’est pas plus mauvaise
qu’une autre pour Ubuntu. Pour Debian, elle ne couvre pas
les mises à jour entre deux versions de la
distribution. De nos jours, il est cependant plutôt
courant de réinstaller un système plutôt que de le mettre
à jour. <a class="footnote-backref" href="#fnref:version" title="Jump back to footnote 4 in the text">↩</a></p>
</li>
<li id="fn:devscripts">
<p>Les paquets <code>devscripts</code> et <code>equivs</code> sont alors nécessaires. <a class="footnote-backref" href="#fnref:devscripts" title="Jump back to footnote 5 in the text">↩</a></p>
</li>
<li id="fn:provided">
<p>Il est également possible d’utiliser le script fourni en
amont. Toutefois, il n’existe pas de script universel
fonctionnant sur toutes les distributions. Il est donc
important de vérifier que ce script est adapté à Debian
en le comparant au squelette et en vérifiant qu’il utilise
bien <code>start-stop-daemon</code> et le fichier
<code>/lib/lsb/init-functions</code>. Si c’est le cas, vous pouvez
le copier vous-même dans
<code>debian/memcached/etc/init.d</code>. <em>debhelper</em> ajoutera les
scripts nécessaires à son intégration. <a class="footnote-backref" href="#fnref:provided" title="Jump back to footnote 6 in the text">↩</a></p>
</li>
<li id="fn:default">
<p>Un utilisateur désireux de modifier certaines options doit
plutôt utiliser <code>systemctl edit</code>. <a class="footnote-backref" href="#fnref:default" title="Jump back to footnote 7 in the text">↩</a></p>
</li>
<li id="fn:bug822670">
<p>Voir <a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?archive=yes&amp;bug=822670">#822670</a> <a class="footnote-backref" href="#fnref:bug822670" title="Jump back to footnote 8 in the text">↩</a></p>
</li>
<li id="fn:naming">
<p>La charte Debian ne se prononce pas sur la convention à
utiliser. Il est courant de préfixer le nom du démon avec
un tiret bas (comme dans les BSD). Un autre usage courant
est d’utiliser <code>Debian-</code> comme préfixe. Cette dernière
méthode a l’inconvénient de produire un nom d’utilisateur
trop long pour être visible dans les utilitaires comme
<code>top</code> et <code>ps</code>. <a class="footnote-backref" href="#fnref:naming" title="Jump back to footnote 9 in the text">↩</a></p>
</li>
<li id="fn:clean">
<p>Il aurait été possible d’appeler <code>dh_auto_clean</code> à la fin de
la cible. Toutefois, nous nous plaçons dans l’hypothèse que
chaque construction est faite sur une nouvelle copie issue
du système de version. <a class="footnote-backref" href="#fnref:clean" title="Jump back to footnote 10 in the text">↩</a></p>
</li>
</ol>
</div>
      </div>
    </content>
  </entry>
  <entry>
    <title type="html">Dépôts APT locaux en entreprise</title>
    <author><name>Vincent Bernat</name></author>
    <link href="https://vincent.bernat.ch/fr/blog/2014-depots-apt-locaux" rel="alternate"/>
    <link href="https://vincent.bernat.ch/fr/blog/2014-depots-apt-locaux#isso-thread" rel="replies" type="text/html"/>
    <updated>2014-04-27T13:43:25Z</updated>
    <id>http://www.luffy.cx/fr/blog/2014-depots-apt-locaux.html</id>

    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p>Distribuer de manière efficace des logiciels sur l’ensemble d’une
plateforme peut être ardu. Chaque distribution fournit un gestionnaire
de paquets qui est généralement bien adapté à cette tâche. Dans le cas
de <a href="https://www.debian.org/" title="Debian, the universal operating system">Debian</a> ou d’une distribution dérivée, il s’agit d’<abbr title="Advanced Packaging Tool">APT</abbr>.</p>
<p>Certains logiciels ne sont pas présents dans les dépôts officiels ou
peuvent être disponibles dans une version trop ancienne. La mise en
place d’un dépôt local permet de contourner cet écueil.</p>
<p>Ce qui est présenté ici a été mis en place pour <a href="https://www.dailymotion.com/" title="Watch, publish, share videos">Dailymotion</a> et a
été fortement inspiré du travail de <a href="https://raphink.info/" title="Blog de Raphaël Pinson">Raphaël Pinson</a> chez Orange.</p>
<div class="toc">
<ul>
<li><a href="#configuration-des-depots-locaux">Configuration des dépôts locaux</a><ul>
<li><a href="#mise-en-place">Mise en place</a></li>
<li><a href="#miroir-local-dune-distribution-officielle">Miroir local d’une distribution officielle</a></li>
<li><a href="#depot-maison">Dépôt maison</a></li>
<li><a href="#miroir-local-de-depots-tiers">Miroir local de dépôts tiers</a></li>
</ul>
</li>
<li><a href="#construction-des-paquets-debian">Construction des paquets Debian</a><ul>
<li><a href="#compilation">Compilation</a></li>
<li><a href="#numerotation-des-versions">Numérotation des versions</a></li>
<li><a href="#envoi">Envoi</a></li>
</ul>
</li>
</ul>
</div>
<h1 id="configuration-des-depots-locaux">Configuration des dépôts locaux</h1>
<p>Les dépôts à mettre en place peuvent se classer dans trois
catégories :</p>
<ol>
<li>
<p>Les <strong>miroirs de distributions</strong>. Ils permettent d’économiser de la
    bande passante, d’obtenir un meilleur débit et un accès permanent
    même lorsque l’accès à Internet est perturbé.</p>
</li>
<li>
<p>Les <strong>dépôts maisons</strong> pour vos propres paquets avec la
    possibilité de passer par une zone de test pour valider les
    paquets sur quelques machines avant de les pousser en production.</p>
</li>
<li>
<p>Les miroirs pour les <strong>dépôts non officiels</strong>, tels que des
    <a href="https://web.archive.org/web/2014/https://help.launchpad.net/Packaging/PPA" title="Personal Package Archives for Ubuntu">PPA Ubuntu</a>. Pour éviter tout changement inattendu,
    de tels dépôts sont aussi dotés d’une zone de test et d’une zone
    de production.</p>
</li>
</ol>
<p>Avant de continuer, il est important de s’accorder sur la terminologie
à employer. Examinons une ligne issue de mon <code>/etc/apt/sources.list</code>:</p>
<div class="language-debian-sourcelist codehilite"><pre><span/><code><span class="k">deb</span><span class="w"> </span><span class="s">http://ftp.debian.org/debian/</span><span class="w"> </span><span class="kp">unstable</span><span class="w"> </span><span class="kp">main</span><span class="w"> </span><span class="kp">contrib</span><span class="w"> </span><span class="kp">non-free</span>
</code></pre></div>

<p>Dans cet exemple, <code>http://ftp.debian.org/debian/</code> est un <strong>dépôt</strong> et
<code>unstable</code> est une <strong>distribution</strong>. Une distribution est divisée en
un certain nombre de <strong>composants</strong>. Nous en avons ici trois : <code>main</code>,
<code>contrib</code> et <code>non-free</code>.</p>
<p>La mise en place des différents dépôts se fera avec le logiciel
<a href="https://web.archive.org/web/2014/http://mirrorer.alioth.debian.org/" title="reprepro: local repositories for Debian packages">reprepro</a>. Ce n’est pas la seule solution disponible mais il est à
la fois plutôt versatile et simple à mettre en place. <em>reprepro</em> ne
gère qu’un seul dépôt. Le premier choix à effectuer est donc de savoir
comment répartir les paquets dans les dépôts, les distributions et les
composants.</p>
<div class="admonition">
<p class="admonition-title">Mise à jour (06.2019)</p>
<p><a href="https://www.aptly.info/" title="aptly: Debian repository management">aptly</a> est une alternative à <em>reprepro</em>. Il gère plusieurs dépôts. Il
propose une API HTTP et il peut conserver plusieurs versions d’un même
paquet. Pour un miroir complet d’une distribution, <em>reprepro</em> reste plus
performant, mais pour le reste, je vous conseille d’utiliser <em>aptly</em>.</p>
</div>
<p>Voici quelques billes pour choisir :</p>
<ul>
<li>Un <strong>dépôt</strong> ne peut pas contenir deux paquets identiques (même
   nom, même version, même architecture).</li>
<li>À l’intérieur d’un <strong>composant</strong>, il n’est possible d’avoir qu’une
   seule version d’un paquet.</li>
<li>Habituellement, une <strong>distribution est un sous-ensemble des
   versions</strong> tandis qu’un <strong>composant est un sous-ensemble des
   paquets</strong>. Par exemple, dans Debian, la distribution <code>unstable</code>
   permet d’obtenir des paquets dans des versions très récentes tandis
   que le composant <code>main</code> permet de se limiter aux paquets respectant
   la <abbr title="Debian Free Software Guidelines">DFSG</abbr>.</li>
</ul>
<p>En partant sur plusieurs dépôts, il faudra gérer plusieurs instances
de <em>reprepro</em> et la copie entre deux instances se fait
manuellement. À <a href="https://www.dailymotion.com/" title="Watch, publish, share videos">Dailymotion</a>, nous sommes partis sur un seul dépôt, mais il aurait été possible de partir sur trois dépôts :</p>
<ul>
<li>un pour les miroirs de distributions,</li>
<li>un pour les paquets maisons,</li>
<li>un pour les miroirs de dépôts tiers.</li>
</ul>
<p>Voici ce que nous allons mettre en place :</p>
<figure class="lf-fullbleed"><div class="lf-media-outer" style="width: 654px"><span class="lf-media-inner" style="padding-bottom: 63.609%"><img alt="Local APT repository" src="https://media-bernat-ch.b-cdn.net/images/apt-repository.559851520741ee.svg" width="654" height="416" class="lf-media"/></span></div><figcaption>Un dépôt avec trois distributions comprenant également une zone de test.</figcaption></figure>
<h2 id="mise-en-place">Mise en place</h2>
<p>La première étape est de créer un utilisateur pour travailler sur les
dépôts :</p>
<div class="language-bash-session codehilite"><pre><span/><code><span class="gp">$ </span>adduser<span class="w"> </span>--system<span class="w"> </span>--disabled-password<span class="w"> </span>--disabled-login<span class="w"> </span><span class="se">\</span>
<span class="gp">&gt; </span><span class="w">        </span>--home<span class="w"> </span>/srv/packages<span class="w"> </span><span class="se">\</span>
<span class="gp">&gt; </span><span class="w">        </span>--group<span class="w"> </span>reprepro
</code></pre></div>

<p>Toutes les opérations qui suivent doivent utiliser exclusivement cet
utilisateur. Chaque dépôt aura son propre répertoire dans lequel on
trouvera les sous-répertoires suivants :</p>
<ul>
<li><code>conf/</code> qui contient les fichiers de configuration,</li>
<li><code>gpg/</code> qui contient les fichiers permettant de signer et
   authentifier les dépôts avec GPG<sup id="fnref:sharegpg"><a class="footnote-ref" href="#fn:sharegpg">1</a></sup>,</li>
<li><code>logs/</code> qui contient les journaux,</li>
<li><code>www/</code> qui contient les fichiers du dépôt à rendre visible par un
   quelconque serveur web.</li>
</ul>
<p>Voici le contenu de <code>conf/options</code> :</p>
<div class="language-text-only codehilite"><pre><span/><code>outdir +b/www
logdir +b/logs
gnupghome +b/gpg
</code></pre></div>

<p>Créons la clé GPG pour signer le dépôt :</p>
<div class="language-bash-session codehilite"><pre><span/><code><span class="gp">$ </span><span class="nv">GNUPGHOME</span><span class="o">=</span>gpg<span class="w"> </span>gpg<span class="w"> </span>--gen-key
<span class="go">Please select what kind of key you want:</span>
<span class="go">   (1) RSA and RSA (default)</span>
<span class="go">   (2) DSA and Elgamal</span>
<span class="go">   (3) DSA (sign only)</span>
<span class="go">   (4) RSA (sign only)</span>
<span class="go">Your selection? 1</span>
<span class="go">RSA keys may be between 1024 and 4096 bits long.</span>
<span class="go">What keysize do you want? (2048) 4096</span>
<span class="go">Requested keysize is 4096 bits</span>
<span class="go">Please specify how long the key should be valid.</span>
<span class="go">         0 = key does not expire</span>
<span class="go">      &lt;n&gt;  = key expires in n days</span>
<span class="go">      &lt;n&gt;w = key expires in n weeks</span>
<span class="go">      &lt;n&gt;m = key expires in n months</span>
<span class="go">      &lt;n&gt;y = key expires in n years</span>
<span class="go">Key is valid for? (0) 10y</span>
<span class="go">Key expires at mer. 08 nov. 2023 22:30:58 CET</span>
<span class="go">Is this correct? (y/N) y</span>

<span class="go">Real name: Dailymotion Archive Automatic Signing Key</span>
<span class="go">Email address: the-it-operations@dailymotion.com</span>
<span class="go">Comment:</span>
<span class="go">[…]</span>
</code></pre></div>

<p>Un mot de passe vide permet à <em>reprepro</em> de tourner sans intervention
de l’utilisateur (notamment pour les mises à jour nocturnes). La clé
publique devra être distribuée pour permettre à <abbr title="Advanced Packaging Tool">APT</abbr> de vérifier les
signatures de l’archive. Une façon commode de faire est de la placer
dans un paquet.</p>
<h2 id="miroir-local-dune-distribution-officielle">Miroir local d’une distribution officielle</h2>
<p>Commençons par mettre en place un miroir pour Ubuntu Precise. Nous
avons besoin de faire deux choses :</p>
<ol>
<li>Configurer une nouvelle <strong>distribution</strong> dans le fichier <code>conf/distributions</code>.</li>
<li>Configurer les <strong>sources</strong> dans le fichier <code>conf/updates</code>.</li>
</ol>
<p>Ajoutons ce bloc dans <code>conf/distributions</code>:</p>
<div class="language-ini codehilite"><pre><span/><code><span class="c1"># Ubuntu Precise</span>
<span class="na">Origin</span><span class="o">:</span><span class="w"> </span><span class="s">Ubuntu</span>
<span class="na">Label</span><span class="o">:</span><span class="w"> </span><span class="s">Ubuntu</span>
<span class="na">Suite</span><span class="o">:</span><span class="w"> </span><span class="s">precise</span>
<span class="na">Version</span><span class="o">:</span><span class="w"> </span><span class="s">12.04</span>
<span class="na">Codename</span><span class="o">:</span><span class="w"> </span><span class="s">precise</span>
<span class="na">Architectures</span><span class="o">:</span><span class="w"> </span><span class="s">i386 amd64</span>
<span class="na">Components</span><span class="o">:</span><span class="w"> </span><span class="s">main restricted universe multiverse</span>
<span class="na">UDebComponents</span><span class="o">:</span><span class="w"> </span><span class="s">main restricted universe multiverse</span>
<span class="na">Description</span><span class="o">:</span><span class="w"> </span><span class="s">Ubuntu Precise 12.04 (with updates and security)</span>
<span class="na">Contents</span><span class="o">:</span><span class="w"> </span><span class="s">.gz .bz2</span>
<span class="na">UDebIndices</span><span class="o">:</span><span class="w"> </span><span class="s">Packages Release . .gz</span>
<span class="na">Tracking</span><span class="o">:</span><span class="w"> </span><span class="s">minimal</span>
<span class="na">Update</span><span class="o">:</span><span class="w"> </span><span class="s">- ubuntu-precise ubuntu-precise-updates ubuntu-precise-security</span>
<span class="na">SignWith</span><span class="o">:</span><span class="w"> </span><span class="s">yes</span>
</code></pre></div>

<p>Il définit la distribution <code>precise</code> dans notre dépôt. Elle contient
quatre composants : <code>main</code>, <code>restricted</code>, <code>universe</code> et <code>multiverse</code>
(comme la distribution présente dans les dépôts officiels).</p>
<p>La ligne <code>Update</code> commence par un tiret. Cela signifie que <em>reprepro</em>
va marquer tous les paquets comme à effacer avant d’appliquer les
mises à jour indiquées. Les paquets supprimés de la distribution
officielle ne seront donc pas conservés dans notre miroir. Dans
<code>conf/updates</code>, nous définissons les sources :</p>
<div class="language-ini codehilite"><pre><span/><code><span class="c1"># Ubuntu Precise</span>
<span class="na">Name</span><span class="o">:</span><span class="w"> </span><span class="s">ubuntu-precise</span>
<span class="na">Method</span><span class="o">:</span><span class="w"> </span><span class="s">http://fr.archive.ubuntu.com/ubuntu</span>
<span class="na">Fallback</span><span class="o">:</span><span class="w"> </span><span class="s">http://de.archive.ubuntu.com/ubuntu</span>
<span class="na">Suite</span><span class="o">:</span><span class="w"> </span><span class="s">precise</span>
<span class="na">Components</span><span class="o">:</span><span class="w"> </span><span class="s">main main multiverse restricted universe</span>
<span class="na">UDebComponents</span><span class="o">:</span><span class="w"> </span><span class="s">main restricted universe multiverse</span>
<span class="na">Architectures</span><span class="o">:</span><span class="w"> </span><span class="s">amd64 i386</span>
<span class="na">VerifyRelease</span><span class="o">:</span><span class="w"> </span><span class="s">437D05B5</span>
<span class="na">GetInRelease</span><span class="o">:</span><span class="w"> </span><span class="s">no</span>

<span class="c1"># Ubuntu Precise Updates</span>
<span class="na">Name</span><span class="o">:</span><span class="w"> </span><span class="s">ubuntu-precise-updates</span>
<span class="na">Method</span><span class="o">:</span><span class="w"> </span><span class="s">http://fr.archive.ubuntu.com/ubuntu</span>
<span class="na">Fallback</span><span class="o">:</span><span class="w"> </span><span class="s">http://de.archive.ubuntu.com/ubuntu</span>
<span class="na">Suite</span><span class="o">:</span><span class="w"> </span><span class="s">precise-updates</span>
<span class="na">Components</span><span class="o">:</span><span class="w"> </span><span class="s">main restricted universe multiverse</span>
<span class="na">UDebComponents</span><span class="o">:</span><span class="w"> </span><span class="s">main restricted universe multiverse</span>
<span class="na">Architectures</span><span class="o">:</span><span class="w"> </span><span class="s">amd64 i386</span>
<span class="na">VerifyRelease</span><span class="o">:</span><span class="w"> </span><span class="s">437D05B5</span>
<span class="na">GetInRelease</span><span class="o">:</span><span class="w"> </span><span class="s">no</span>

<span class="c1"># Ubuntu Precise Security</span>
<span class="na">Name</span><span class="o">:</span><span class="w"> </span><span class="s">ubuntu-precise-security</span>
<span class="na">Method</span><span class="o">:</span><span class="w"> </span><span class="s">http://fr.archive.ubuntu.com/ubuntu</span>
<span class="na">Fallback</span><span class="o">:</span><span class="w"> </span><span class="s">http://de.archive.ubuntu.com/ubuntu</span>
<span class="na">Suite</span><span class="o">:</span><span class="w"> </span><span class="s">precise-security</span>
<span class="na">Components</span><span class="o">:</span><span class="w"> </span><span class="s">main restricted universe multiverse</span>
<span class="na">UDebComponents</span><span class="o">:</span><span class="w"> </span><span class="s">main restricted universe multiverse</span>
<span class="na">Architectures</span><span class="o">:</span><span class="w"> </span><span class="s">amd64 i386</span>
<span class="na">VerifyRelease</span><span class="o">:</span><span class="w"> </span><span class="s">437D05B5</span>
<span class="na">GetInRelease</span><span class="o">:</span><span class="w"> </span><span class="s">no</span>
</code></pre></div>

<p>Les lignes <code>VerifyRelease</code> indiquent les empreintes des clefs GPG à
utiliser pour vérifier la signature des dépôts distants. Il faut
importer la clé en question dans l’anneau local :</p>
<div class="language-bash-session codehilite"><pre><span/><code><span class="gp">$ </span>gpg<span class="w"> </span>--keyring<span class="w"> </span>/usr/share/keyrings/ubuntu-archive-keyring.gpg<span class="w"> </span><span class="se">\</span>
<span class="gp">&gt; </span><span class="w">    </span>--export<span class="w"> </span>437D05B5<span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nv">GNUPGHOME</span><span class="o">=</span>gpg<span class="w"> </span>gpg<span class="w"> </span>--import
</code></pre></div>

<p>Un autre point important est le fait que nous avons fusionné trois
distributions (<code>precise</code>, <code>precise-updates</code> et <code>precise-security</code>)
dans une seule distribution (<code>precise</code>) dans notre dépôt local. Cela
peut provoquer des difficultés avec les outils, tels que le Debian
Installer<sup id="fnref:installer"><a class="footnote-ref" href="#fn:installer">2</a></sup>, qui s’attendent à trouver les trois
distributions classiques.</p>
<p>Il est ensuite possible de lancer <em>reprepro</em> pour mettre à jour le
miroir :</p>
<div class="language-bash-session codehilite"><pre><span/><code><span class="gp">$ </span>reprepro<span class="w"> </span>update
</code></pre></div>

<p>Cela prend un certain temps la première fois. <em>reprepro</em> n’est pas la
solution la plus efficace pour mettre en place un miroir, mais sa
prise en main est simple et il est particulièrement fiable.</p>
<h2 id="depot-maison">Dépôt maison</h2>
<p>Passons au dépôt pour les paquets maisons. Pour chaque distribution
officielle (telle que <code>precise</code>), nous mettons en place deux
distributions :</p>
<ul>
<li><code>precise-staging</code> contient les paquets en cours de test.</li>
<li><code>precise-prod</code> contient les paquets testés issus de
   <code>precise-staging</code>.</li>
</ul>
<p>Dans cette organisation, les paquets sont introduits dans
<code>precise-staging</code> où ils peuvent être testés sur quelques serveurs
avant d’être copiés dans <code>precise-prod</code> pour être disponibles sur
l’ensemble de la plateforme. La déclaration dans <code>conf/distributions</code>
se fait ainsi :</p>
<div class="language-ini codehilite"><pre><span/><code><span class="c1"># Dailymotion Precise packages (staging)</span>
<span class="na">Origin</span><span class="o">:</span><span class="w"> </span><span class="s">Dailymotion</span><span class="w"> </span><span class="c1"># ❸</span>
<span class="na">Label</span><span class="o">:</span><span class="w"> </span><span class="s">dm-staging</span><span class="w">   </span><span class="c1"># ❸</span>
<span class="na">Suite</span><span class="o">:</span><span class="w"> </span><span class="s">precise-staging</span>
<span class="na">Codename</span><span class="o">:</span><span class="w"> </span><span class="s">precise-staging</span>
<span class="na">Architectures</span><span class="o">:</span><span class="w"> </span><span class="s">i386 amd64 source</span>
<span class="na">Components</span><span class="o">:</span><span class="w"> </span><span class="s">main role/dns role/database role/web</span><span class="w"> </span><span class="c1"># ❶</span>
<span class="na">Description</span><span class="o">:</span><span class="w"> </span><span class="s">Dailymotion Precise staging repository</span>
<span class="na">Contents</span><span class="o">:</span><span class="w"> </span><span class="s">.gz .bz2</span>
<span class="na">Tracking</span><span class="o">:</span><span class="w"> </span><span class="s">keep</span>
<span class="na">SignWith</span><span class="o">:</span><span class="w"> </span><span class="s">yes</span>
<span class="na">NotAutomatic</span><span class="o">:</span><span class="w"> </span><span class="s">yes</span><span class="w"> </span><span class="c1"># ❷</span>
<span class="na">Log</span><span class="o">:</span><span class="w"> </span><span class="s">packages.dm-precise-staging.log</span>
<span class="w"> </span><span class="na">--type</span><span class="o">=</span><span class="s">dsc email-changes</span>

<span class="c1"># Dailymotion Precise packages (prod)</span>
<span class="na">Origin</span><span class="o">:</span><span class="w"> </span><span class="s">Dailymotion</span><span class="w"> </span><span class="c1"># ❸</span>
<span class="na">Label</span><span class="o">:</span><span class="w"> </span><span class="s">dm-prod</span><span class="w">      </span><span class="c1"># ❸</span>
<span class="na">Suite</span><span class="o">:</span><span class="w"> </span><span class="s">precise-prod</span>
<span class="na">Codename</span><span class="o">:</span><span class="w"> </span><span class="s">precise-prod</span>
<span class="na">Architectures</span><span class="o">:</span><span class="w"> </span><span class="s">i386 amd64 source</span>
<span class="na">Components</span><span class="o">:</span><span class="w"> </span><span class="s">main role/dns role/database role/web</span><span class="w"> </span><span class="c1"># ❶</span>
<span class="na">Description</span><span class="o">:</span><span class="w"> </span><span class="s">Dailymotion Precise prod repository</span>
<span class="na">Contents</span><span class="o">:</span><span class="w"> </span><span class="s">.gz .bz2</span>
<span class="na">Tracking</span><span class="o">:</span><span class="w"> </span><span class="s">keep</span>
<span class="na">SignWith</span><span class="o">:</span><span class="w"> </span><span class="s">yes</span>
<span class="na">Log</span><span class="o">:</span><span class="w"> </span><span class="s">packages.dm-precise-prod.log</span>
</code></pre></div>

<p>Notez d’abord l’utilisation de plusieurs composants (en ❶) :</p>
<ul>
<li><code>main</code> contiendra les paquets génériques. Un paquet placé dans
   <code>main</code> doit pouvoir être utilisé sur n’importe quel serveur.</li>
<li><code>role/*</code> sont des composants dédiés à un sous-ensemble de la
   plateforme. Par exemple, dans <code>role/dns</code>, on trouvera des versions
   modifiées de <em>BIND</em>.</li>
</ul>
<p>La distribution de test utilise le drapeau <code>NotAutomatic</code> (en ❷) qui
indique au gestionnaire de paquets de ne pas installer ces paquets à
moins d’une requête expresse de l’utilisateur. Juste au-dessous, quand
un nouveau fichier <code>dsc</code> est reçu, le script
<a href="https://gist.github.com/vincentbernat/7404733" title="Crochet email-changes pour reprepro"><code>email-changes</code></a> est exécuté. Il doit se trouver dans
le répertoire <code>conf/</code>.</p>
<p>Les lignes <code>Origin</code> et <code>Label</code> (en ❸) sont particulièrement importantes
car elles seront utilisées pour déterminer la politique d’installation
des paquets. Prenons ce fichier <code>/etc/apt/sources.list</code> :</p>
<div class="language-debian-sourcelist codehilite"><pre><span/><code><span class="c"># Ubuntu packages</span>
<span class="k">deb</span><span class="w"> </span><span class="s">http://packages.dm.gg/dailymotion</span><span class="w"> </span><span class="kp">precise</span><span class="w"> </span><span class="kp">main</span><span class="w"> </span><span class="kp">restricted</span><span class="w"> </span><span class="kp">universe</span><span class="w"> </span><span class="kp">multiverse</span>

<span class="c"># Dailymotion packages</span>
<span class="k">deb</span><span class="w"> </span><span class="s">http://packages.dm.gg/dailymotion</span><span class="w"> </span><span class="kp">precise-prod</span><span class="w">    </span><span class="kp">main</span><span class="w"> </span><span class="kp">role/dns</span>
<span class="k">deb</span><span class="w"> </span><span class="s">http://packages.dm.gg/dailymotion</span><span class="w"> </span><span class="kp">precise-staging</span><span class="w"> </span><span class="kp">main</span><span class="w"> </span><span class="kp">role/dns</span>
</code></pre></div>

<p>Tous les serveurs peuvent utiliser la distribution
<code>precise-staging</code>. Il est essentiel de ne pas installer par erreur des
paquets de cette distribution. Le drapeau <code>NotAutomatic</code> est une
première sécurité. Nous y ajoutons ce fichier <code>/etc/apt/preferences</code> :</p>
<div class="language-text-only codehilite"><pre><span/><code>Explanation: Dailymotion packages of a specific component should be more preferred
Package: *
Pin: release o=Dailymotion, l=dm-prod, c=role/*
Pin-Priority: 950

Explanation: Dailymotion packages should be preferred
Package: *
Pin: release o=Dailymotion, l=dm-prod
Pin-Priority: 900

Explanation: staging should never be preferred
Package: *
Pin: release o=Dailymotion, l=dm-staging
Pin-Priority: -100
</code></pre></div>

<p>Par défaut, les paquets ont une priorité de 500. En utilisant une
priorité de -100 pour les paquets en provenance de la distribution de
test, nous nous assurons qu’ils ne peuvent pas être installés du
tout. C’est une contrainte plus forte que l’utilisation de
<code>NotAutomatic</code> qui place la priorité à 1. Nous favorisons les paquets
se trouvant dans le dépôt maison par rapport aux paquets officiels en
leur affectant une priorité de 900 (voire 950 pour les paquets qui se
trouvent dans un composant type rôle).</p>
<p>La section “<em>How <abbr title="Advanced Packaging Tool">APT</abbr> Interprets Priorities</em>” de la page de manuel
<a href="https://manpages.debian.org/apt_preferences.5.html" title="Page de manuel pour apt_preferences(5)"><code>apt_preferences(5)</code></a> donne plus de détails. Il faut
garder en tête que les versions ne sont utilisées qu’à priorité
égale. La commande <code>apt-cache policy</code> permet de vérifier que tout
fonctionne comme attendu :</p>
<div class="language-bash-session codehilite"><pre><span/><code><span class="gp">$ </span>apt-cache<span class="w"> </span>policy<span class="w"> </span>php5-memcache
<span class="go">  Installed: 3.0.8-1~precise2~dm1</span>
<span class="go">  Candidate: 3.0.8-1~precise2~dm1</span>
<span class="go">  Version table:</span>
<span class="go"> *** 3.0.8-1~precise2~dm1 0</span>
<span class="go">        950 http://packages.dm.gg/dailymotion/ precise-prod/role/web amd64 Packages</span>
<span class="go">        100 /var/lib/dpkg/status</span>
<span class="go">     3.0.8-1~precise1~dm4 0</span>
<span class="go">        900 http://packages.dm.gg/dailymotion/ precise-prod/main amd64 Packages</span>
<span class="go">       -100 http://packages.dm.gg/dailymotion/ precise-staging/main amd64 Packages</span>
<span class="go">     3.0.6-1 0</span>
<span class="go">        500 http://packages.dm.gg/dailymotion/ precise/universe amd64 Packages</span>
</code></pre></div>

<p>Pour installer un paquet en provenance de la distribution de test, il
suffit d’invoquer <code>apt-get</code> avec l’option <code>-t precise-staging</code> qui
augmente la priorité de cette distribution à 990.</p>
<p>Une fois le paquet testé sur quelques serveurs, il est possible de le
copier vers la distribution de production :</p>
<div class="language-bash-session codehilite"><pre><span/><code><span class="gp">$ </span>reprepro<span class="w"> </span>-C<span class="w"> </span>main<span class="w"> </span>copysrc<span class="w"> </span>precise-prod<span class="w"> </span>precise-staging<span class="w"> </span>wackadoodle
</code></pre></div>

<h2 id="miroir-local-de-depots-tiers">Miroir local de dépôts tiers</h2>
<p>Parfois, plutôt que de reconstruire un paquet, il est préférable de le
prendre directement sur un dépôt tiers. Un exemple courant est les
dépôts mis en place par les constructeurs. Comme pour la mise en place
d’un miroir d’une distribution officielle, il y a deux étapes :
définition de la distribution et déclaration des sources.</p>
<p>Chaque miroir va se trouver dans les mêmes distributions que nos
paquets maisons mais ils iront dans un composant dédié. Cela nous
permet d’utiliser la même organisation que pour les paquets locaux :
ils apparaîtront dans la distribution de test avant d’être
manuellement copiés, après validation, dans la distribution de
production.</p>
<p>La première étape consiste à ajouter le composant et la ligne <code>Update</code>
appropriée dans le fichier <code>conf/distributions</code> :</p>
<div class="language-ini codehilite"><pre><span/><code><span class="na">Origin</span><span class="o">:</span><span class="w"> </span><span class="s">Dailymotion</span>
<span class="na">Label</span><span class="o">:</span><span class="w"> </span><span class="s">dm-staging</span>
<span class="na">Suite</span><span class="o">:</span><span class="w"> </span><span class="s">precise-staging</span>
<span class="na">Components</span><span class="o">:</span><span class="w"> </span><span class="s">main role/dns role/database role/web vendor/hp</span>
<span class="na">Update</span><span class="o">:</span><span class="w"> </span><span class="s">hp</span>
<span class="c1"># […]</span>

<span class="na">Origin</span><span class="o">:</span><span class="w"> </span><span class="s">Dailymotion</span>
<span class="na">Label</span><span class="o">:</span><span class="w"> </span><span class="s">dm-prod</span>
<span class="na">Suite</span><span class="o">:</span><span class="w"> </span><span class="s">precise-prod</span>
<span class="na">Components</span><span class="o">:</span><span class="w"> </span><span class="s">main role/dns role/database role/web vendor/hp</span>
<span class="c1"># […]</span>
</code></pre></div>

<p>Le composant <code>vendor/hp</code> a été ajouté aux deux distributions mais
seule la distribution de test a une ligne <code>Update</code>. La distribution de
production obtiendra les paquets par copie manuelle.</p>
<p>La source des paquets est déclarée dans le fichier <code>conf/updates</code> :</p>
<div class="language-ini codehilite"><pre><span/><code><span class="c1"># HP repository</span>
<span class="na">Name</span><span class="o">:</span><span class="w"> </span><span class="s">hp</span>
<span class="na">Method</span><span class="o">:</span><span class="w"> </span><span class="s">http://downloads.linux.hp.com/SDR/downloads/ManagementComponentPack/</span>
<span class="na">Suite</span><span class="o">:</span><span class="w"> </span><span class="s">precise/current</span>
<span class="na">Components</span><span class="o">:</span><span class="w"> </span><span class="s">non-free&gt;vendor/hp</span>
<span class="na">Architectures</span><span class="o">:</span><span class="w"> </span><span class="s">i386 amd64</span>
<span class="na">VerifyRelease</span><span class="o">:</span><span class="w"> </span><span class="s">2689B887</span>
<span class="na">GetInRelease</span><span class="o">:</span><span class="w"> </span><span class="s">no</span>
</code></pre></div>

<p>N’oubliez pas de rajouter la clé GPG correspondante dans l’anneau
local. À noter une fonctionnalité particulièrement intéressante de
<em>reprepro</em> qui permet de copier le composant <code>non-free</code> dans le
composant <code>vendor/hp</code>.</p>
<h1 id="construction-des-paquets-debian">Construction des paquets Debian</h1>
<p>La configuration de <em>reprepro</em> est désormais terminée. Comment
construire les paquets à placer dans la distribution de test ?</p>
<p>Selon le temps que vous souhaitez accorder à cette activité, il y a
plusieurs possibilités :</p>
<ol>
<li>
<p>Construire un <strong>paquet source</strong> en ajoutant un répertoire
    <code>debian/</code>. C’est la façon classique. Il est possible de partir de
    zéro ou de prendre un paquet existant dans une distribution plus
    récente ou un rétroportage d’un dépôt non officiel.</p>
</li>
<li>
<p>Utiliser un <strong>outil qui va créer un paquet binaire à partir d’un
    répertoire</strong>, tel que <a href="https://github.com/jordansissel/fpm" title="fpm: Effing package managers">fpm</a>. Un tel outil va minimiser le boulot
    à effectuer pour construire un paquet et peut même empaqueter
    automatiquement certains types de logiciels.</p>
</li>
</ol>
<p>Il n’y a pas de solution universelle. La première approche est plus
chronophage mais dispose des avantages suivants :</p>
<ul>
<li>
<p>Les <strong>sources restent disponibles dans le dépôt</strong>. Si vous avez
   besoin de reconstruire un paquet en urgence pour corriger un
   problème, il n’est pas nécessaire de partir à la recherche des
   sources qui peuvent être temporairement indisponibles. Bien sûr,
   cela n’est valable que pour les paquets qui ne téléchargent pas les
   dépendances depuis Internet.</p>
</li>
<li>
<p>La <strong>recette de construction est conservée</strong><sup id="fnref:recipe"><a class="footnote-ref" href="#fn:recipe">3</a></sup> dans le
   dépôt. Si quelqu’un active telle option et reconstruit le paquet,
   cette option ne sera pas perdue lorsqu’une autre personne reconstruira
   le paquet. Ces changements sont documentés dans le fichier
   <code>debian/changelog</code>. De plus, un système de gestion des versions
   peut être utilisé pour garder une trace précise des changements
   liés à l’empaquetage.</p>
</li>
<li>
<p>Le paquet obtenu peut ensuite être proposé à l’<strong>inclusion dans
   Debian</strong>. Cela rendra service à de nombreuses autres personnes.</p>
</li>
</ul>
<div class="admonition">
<p class="admonition-title">Mise à jour (10.2017)</p>
<p>Je présente une approche alternative pour créer des paquets Debian sans trop
d’effort dans « <a href="/fr/blog/2016-empaquetage-debian-empirique" title="Petit traité empirique de l'empaquetage Debian">Petit traité empirique de l’empaquetage Debian</a> ».</p>
</div>
<h2 id="compilation">Compilation</h2>
<p><a href="https://pbuilder-docs.readthedocs.io/en/latest/index.html" title="pbuilder users's manual">pbuilder</a> est utilisé pour la compilation automatique des
paquets<sup id="fnref:vssbuild"><a class="footnote-ref" href="#fn:vssbuild">4</a></sup>. Sa mise en place est relativement simple. Voici le
fichier <code>pbuilderrc</code> utilisé :</p>
<div class="language-bash codehilite"><pre><span/><code><span class="nv">DISTRIBUTION</span><span class="o">=</span><span class="nv">$DIST</span>
<span class="nv">NAME</span><span class="o">=</span><span class="s2">"</span><span class="nv">$DIST</span><span class="s2">-</span><span class="nv">$ARCH</span><span class="s2">"</span>
<span class="nv">MIRRORSITE</span><span class="o">=</span>http://packages.dm.gg/dailymotion
<span class="nv">COMPONENTS</span><span class="o">=(</span><span class="s2">"main"</span><span class="w"> </span><span class="s2">"restricted"</span><span class="w"> </span><span class="s2">"universe"</span><span class="w"> </span><span class="s2">"multiverse"</span><span class="o">)</span>
<span class="nv">OTHERMIRROR</span><span class="o">=</span><span class="s2">"deb http://packages.dm.gg/dailymotion </span><span class="si">${</span><span class="nv">DIST</span><span class="si">}</span><span class="s2">-staging main"</span>
<span class="nv">HOOKDIR</span><span class="o">=</span>/etc/pbuilder/hooks.d
<span class="nv">BASE</span><span class="o">=</span>/var/cache/pbuilder/dailymotion
<span class="nv">BASETGZ</span><span class="o">=</span><span class="nv">$BASE</span>/<span class="nv">$NAME</span>/base.tgz
<span class="nv">BUILDRESULT</span><span class="o">=</span><span class="nv">$BASE</span>/<span class="nv">$NAME</span>/results/
<span class="nv">APTCACHE</span><span class="o">=</span><span class="nv">$BASE</span>/<span class="nv">$NAME</span>/aptcache/
<span class="nv">DEBBUILDOPTS</span><span class="o">=</span><span class="s2">"-sa"</span>
<span class="nv">KEYRING</span><span class="o">=</span><span class="s2">"/usr/share/keyrings/dailymotion-archive.keyring.gpg"</span>
<span class="nv">DEBOOTSTRAPOPTS</span><span class="o">=(</span><span class="s2">"--arch"</span><span class="w"> </span><span class="s2">"</span><span class="nv">$ARCH</span><span class="s2">"</span><span class="w"> </span><span class="s2">"--variant=buildd"</span><span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">DEBOOTSTRAPOPTS</span><span class="p">[@]</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span><span class="s2">"--keyring=</span><span class="nv">$KEYRING</span><span class="s2">"</span><span class="o">)</span>
<span class="nv">APTKEYRINGS</span><span class="o">=(</span><span class="s2">"</span><span class="nv">$KEYRING</span><span class="s2">"</span><span class="o">)</span>
<span class="nv">EXTRAPACKAGES</span><span class="o">=(</span><span class="s2">"dailymotion-archive-keyring"</span><span class="o">)</span>
</code></pre></div>

<p><code>pbuilder</code> doit être invoqué avec les variables d’environnement
<code>DIST</code>, <code>ARCH</code> et (optionnellement) <code>ROLE</code>. La mise en place de chaque
environnement s’effectue ainsi :</p>
<div class="language-bash codehilite"><pre><span/><code><span class="k">for</span><span class="w"> </span>ARCH<span class="w"> </span><span class="k">in</span><span class="w"> </span>i386<span class="w"> </span>amd64<span class="p">;</span><span class="w"> </span><span class="k">do</span>
<span class="w">  </span><span class="k">for</span><span class="w"> </span>DIST<span class="w"> </span><span class="k">in</span><span class="w"> </span>precise<span class="p">;</span><span class="w"> </span><span class="k">do</span>
<span class="w">    </span><span class="nb">export</span><span class="w"> </span>ARCH
<span class="w">    </span><span class="nb">export</span><span class="w"> </span>DIST
<span class="w">    </span>pbuilder<span class="w"> </span>--create
<span class="w">  </span><span class="k">done</span>
<span class="k">done</span>
</code></pre></div>

<p>Concernant les rôles, un crochet de type <code>D</code> permet d’ajouter les
sources appropriées avant la compilation :</p>
<div class="language-bash codehilite"><pre><span/><code><span class="ch">#!/bin/bash</span>
<span class="o">[</span><span class="w"> </span>-z<span class="w"> </span><span class="s2">"</span><span class="nv">$ROLE</span><span class="s2">"</span><span class="w"> </span><span class="o">]</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="o">{</span>
<span class="w">  </span>cat<span class="w"> </span>&gt;&gt;<span class="w"> </span>/etc/apt/sources.list<span class="w"> </span><span class="s">&lt;&lt;EOF</span>
<span class="s">deb http://packages.dm.gg/dailymotion ${DIST}-staging role/${ROLE}</span>
<span class="s">EOF</span>
<span class="o">}</span>

apt-get<span class="w"> </span>update
</code></pre></div>

<p>Un crochet de type <code>E</code> permet de s’assurer que les paquets de la
distribution de test sont prioritairement utilisés pour la
construction :</p>
<div class="language-bash codehilite"><pre><span/><code><span class="ch">#!/bin/bash</span>

cat<span class="w"> </span>&gt;<span class="w"> </span>/etc/apt/preferences<span class="w"> </span><span class="s">&lt;&lt;EOF</span>
<span class="s">Explanation: Dailymotion packages are of higher priority</span>
<span class="s">Package: *</span>
<span class="s">Pin: release o=Dailymotion</span>
<span class="s">Pin-Priority: 900</span>
<span class="s">EOF</span>
</code></pre></div>

<p>Enfin, un crochet de type <code>C</code> permet d’obtenir un shell en cas
d’erreur, ce qui est pratique pour corriger un problème :</p>
<div class="language-bash codehilite"><pre><span/><code><span class="ch">#!/bin/bash</span>
apt-get<span class="w"> </span>install<span class="w"> </span>-y<span class="w"> </span>--force-yes<span class="w"> </span>vim<span class="w"> </span>less
<span class="nb">cd</span><span class="w"> </span>/tmp/buildd/*/debian/..
/bin/bash<span class="w"> </span>&lt;<span class="w"> </span>/dev/tty<span class="w"> </span>&gt;<span class="w"> </span>/dev/tty<span class="w"> </span><span class="m">2</span>&gt;<span class="w"> </span>/dev/tty
</code></pre></div>

<p>Une compilation peut ensuite être lancée avec la commande :</p>
<div class="language-bash-session codehilite"><pre><span/><code><span class="gp">$ </span><span class="nv">ARCH</span><span class="o">=</span>amd64<span class="w"> </span><span class="nv">DIST</span><span class="o">=</span>precise<span class="w"> </span><span class="nv">ROLE</span><span class="o">=</span>web<span class="w"> </span>pbuilder<span class="w"> </span><span class="se">\</span>
<span class="gp">&gt; </span><span class="w">        </span>--build<span class="w"> </span>somepackage.dsc
</code></pre></div>

<h2 id="numerotation-des-versions">Numérotation des versions</h2>
<p>Afin d’éviter des règles trop complexes pour les versions, tout paquet
est traité comme étant un rétroportage. Le schéma utilisé est le
suivant : <code>X-Y~preciseZ+dmW</code>.</p>
<ul>
<li>
<p><code>X</code> est la version amont<sup id="fnref:snapshot"><a class="footnote-ref" href="#fn:snapshot">5</a></sup>.</p>
</li>
<li>
<p><code>Y</code> est la version Debian. S’il n’y a pas de version Debian, mettre 0.</p>
</li>
<li>
<p><code>Z</code> est la version du backport dans Ubuntu. S’il n’existe pas, mettre 0.</p>
</li>
<li>
<p><code>W</code> est notre version du paquet. Il est incrémenté à chaque
   changement dans le paquet. C’est le seul numéro que nous
   contrôlons. Tous les autres dépendent d’une entité en amont.</p>
</li>
</ul>
<p>Supposons que l’on désire rétroporter le paquet <code>wackadoodle</code>. Il est
disponible dans une Ubuntu plus récente en version <code>1.4-3</code>. La
première version du paquet aura pour version
<code>1.4-3~precise0+dm1</code>. Après un changement dans le fichier
<code>debian/rules</code>, nous obtenons la version <code>1.4-3~precise0+dm2</code>. En
amont, une version <code>1.5</code> devient disponible. Elle n’est disponible ni
dans Ubuntu, ni dans Debian. Le numéro de version du paquet sera alors
<code>1.5-0~precise0+dm1</code>.</p>
<p>Quelques semaines plus tard, le paquet arrive chez Ubuntu dans la
version <code>1.5-3ubuntu1</code>. Vous y appliquez des changements pour obtenir
la version <code>1.5-3ubuntu1~precise0+dm1</code>.</p>
<p>Une convention compatible avec les pratiques de Debian concernant les
rétroportages est : <code>X-Y~bpo70+Z~dm+W</code>.</p>
<h2 id="envoi">Envoi</h2>
<p>Pour intégrer un paquet dans le dépôt, les étapes classiques sont les
suivantes :</p>
<ol>
<li>Le paquet source est placé dans un répertoire <code>incoming/</code>.</li>
<li><em>reprepro</em> remarque le paquet <em>source</em>, vérifie sa validité
    (signature, distribution) et le place dans l’archive.</li>
<li>Le système de compilation remarque un nouveau paquet source à
    construire et lance la compilation de celui-ci.</li>
<li>Une fois les paquets binaires construits, ils sont également
    placés dans le répertoire <code>incoming/</code>.</li>
<li><em>reprepro</em> détecte les paquets <em>binaires</em> et les intègre dans
    l’archive.</li>
</ol>
<p>Cette façon de faire a le désavantage d’être difficile à suivre pour
l’utilisateur. Une alternative est de concevoir un script de
construction exécutant chaque tâche de manière synchrone et permettant
ainsi à l’utilisateur de suivre son terminal le bon déroulement des
opérations. Ce script s’occupe également d’inclure les paquets finaux
dans l’archive :</p>
<div class="language-bash-session codehilite"><pre><span/><code><span class="gp">$ </span>reprepro<span class="w"> </span>-C<span class="w"> </span>main<span class="w"> </span>include<span class="w"> </span>precise-staging<span class="w"> </span><span class="se">\</span>
<span class="gp">&gt; </span><span class="w">     </span>wackadoodle_1.4-3~precise0+dm4_amd64.changes
</code></pre></div>

<p>Voilà !</p>
<div class="footnote">
<hr/>
<ol>
<li id="fn:sharegpg">
<p>Le répertoire <code>gpg/</code> peut être partagé par plusieurs
dépôts. <a class="footnote-backref" href="#fnref:sharegpg" title="Jump back to footnote 1 in the text">↩</a></p>
</li>
<li id="fn:installer">
<p>Il est possible d’apprendre à l’installeur Debian de
travailler avec un tel dépôt en utilisant un <a href="https://gist.github.com/vincentbernat/7412457" title="Fichier de preseed pour l'installeur Debian">fichier de configuration approprié</a>. <a class="footnote-backref" href="#fnref:installer" title="Jump back to footnote 2 in the text">↩</a></p>
</li>
<li id="fn:recipe">
<p><a href="https://github.com/bernd/fpm-cookery" title="A tool for building software packages with fpm">fpm-cookery</a> est un outil particulièrement pratique
pour <a href="https://github.com/jordansissel/fpm" title="fpm: Effing package managers">fpm</a>, dans la même veine que <a href="https://mxcl.dev/homebrew/" title="Homebrew: the missing package manager for OS X">Homebrew</a> ou que
l’arbre de ports des BSD. Il peut être utilisé dans une
optique similaire. <a class="footnote-backref" href="#fnref:recipe" title="Jump back to footnote 3 in the text">↩</a></p>
</li>
<li id="fn:vssbuild">
<p><a href="https://wiki.debian.org/sbuild" title="sbuild">sbuild</a> est une alternative qui est aussi l’outil
utilisé officiellement par Ubuntu et
Debian. Historiquement, <em>pbuilder</em> était plus orienté
vers les besoins des développeurs. <a class="footnote-backref" href="#fnref:vssbuild" title="Jump back to footnote 4 in the text">↩</a></p>
</li>
<li id="fn:snapshot">
<p>Pour un extrait de dépôt Git, le numéro de version amont
utilisé ressemble à <code>1.4-git20130905+1-ae42dc1</code> ce qui
correspond à un extrait situé après la version 1.4
(utiliser 0.0 s’il n’y a jamais eu de publication) à la
date donnée. Le chiffre qui suit la date peut être
incrémenté si plusieurs extraits sont utilisés dans la
même journée. Enfin, le condensat à la fin permet de
récupérer l’extrait exact. <a class="footnote-backref" href="#fnref:snapshot" title="Jump back to footnote 5 in the text">↩</a></p>
</li>
</ol>
</div>
      </div>
    </content>
  </entry>
</feed>