tag:linuxfr.org,2005:/tags/paquet/publicLinuxFr.org : les contenus étiquetés avec « paquet »2023-05-21T15:47:15+02:00/favicon.pngtag:linuxfr.org,2005:Bookmark/65002023-05-21T15:47:15+02:002023-05-21T15:47:15+02:00La migration des fichiers sources de paquet Archlinux sur une instance Gitlab est terminée<a href="https://archlinux.org/news/git-migration-completed/">https://archlinux.org/news/git-migration-completed/</a> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/131304/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/vendrediouletrollsauvage/liens/la-migration-des-fichiers-sources-de-paquet-archlinux-sur-une-instance-gitlab-est-terminee#comments">ouvrir dans le navigateur</a>
</p>
voltshttps://linuxfr.org/nodes/131304/comments.atomtag:linuxfr.org,2005:Bookmark/56232022-12-18T19:58:49+01:002022-12-18T19:58:49+01:00On Flatpak disk usage and deduplication - Will Thompson (Endless OS)<a href="https://blogs.gnome.org/wjjt/2021/11/24/on-flatpak-disk-usage-and-deduplication/">https://blogs.gnome.org/wjjt/2021/11/24/on-flatpak-disk-usage-and-deduplication/</a> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/129706/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/antistress/liens/on-flatpak-disk-usage-and-deduplication-will-thompson-endless-os#comments">ouvrir dans le navigateur</a>
</p>
antistresshttps://linuxfr.org/nodes/129706/comments.atomtag:linuxfr.org,2005:News/412422022-11-04T21:36:18+01:002022-11-04T21:36:18+01:00Jubako et Arx, un conteneur universel et son format d’archiveLicence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<div><h2 id="toc-jubako-quezako">Jubako, quezako ?</h2>
<p><a href="https://en.wikipedia.org/wiki/J%C5%ABbako">重箱 (Jūbako)</a> est le nom japonais des boîtes à bento. Ce sont des boîtes compartimentées qui peuvent se composer en fonction de ce qu’il y a à stocker dedans (en général un repas).</p>
<p>Et ça tombe bien, parce que Jubako, c’est un format de conteneur qui permet de stocker différentes données et méta-données. J’ai tendance à parler de conteneurs plutôt que d’archives, en effet « archive » est un mot orienté qui fait penser aux archives de fichiers, alors que Jubako se veut généraliste : un conteneur Jubako pourrait être utilisé pour plein d’autres choses : empaquetage d’applications, pack de ressources dans un binaire, conteneur multimédia, etc.</p>
<p>Vous pouvez voir Jubako comme étant au stockage ce que XML est à la sérialisation. XML définit comment sérialiser du contenu (sous forme d’un arbre de nœuds avec des attributs) mais ne définit pas quels sont ces nœuds et attributs. Chaque cas d’usage a sa propre structure. Pour Jubako c’est pareil, il définit comment stocker des données dans un fichier « d’archive » mais il ne définit pas quelles sont ces données. Chaque cas d’usage aura sa propre structure de données.</p>
<p>Jubako et Arx sont sous licence MIT.</p>
</div><ul><li>lien nᵒ 1 : <a title="https://framagit.org/jubako/spec" hreflang="en" href="https://linuxfr.org/redirect/111210">Les spécifications de Jubako</a></li><li>lien nᵒ 2 : <a title="https://framagit.org/jubako/jubako" hreflang="wq" href="https://linuxfr.org/redirect/111211">Les sources de la bibliothèque Jubako</a></li><li>lien nᵒ 3 : <a title="https://framagit.org/jubako/arx" hreflang="wq" href="https://linuxfr.org/redirect/111212">Les sources de l'outil d'archivage Arx</a></li></ul><div><h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li><a href="#toc-un-peu-de-contexte">Un peu de contexte</a></li>
<li><a href="#toc-le-format-jubako">Le format Jubako</a></li>
<li><a href="#toc-la-biblioth%C3%A8que-jubako">La bibliothèque Jubako</a></li>
<li>
<a href="#toc-loutil-arx">L’outil Arx</a><ul>
<li><a href="#toc-tar">Tar</a></li>
<li><a href="#toc-le-format-arx"> Le format Arx</a></li>
<li>
<a href="#toc-un-peu-de-comparaison">Un peu de comparaison</a><ul>
<li><a href="#toc-pour-la-partie-documentation-seulement-9194-entr%C3%A9es">Pour la partie documentation seulement (9194 entrées) :</a></li>
<li><a href="#toc-pour-la-partie-drivers-seulement-33056-entr%C3%A9es">Pour la partie drivers seulement (33056 entrées) :</a></li>
<li><a href="#toc-et-pour-les-sources-compl%C3%A8tes-81958-entr%C3%A9es">Et pour les sources complètes (81958 entrées) :</a></li>
<li><a href="#toc-la-taille">La taille</a></li>
<li><a href="#toc-le-temps-de-cr%C3%A9ation">Le temps de création</a></li>
<li><a href="#toc-le-temps-dextraction">Le temps d’extraction</a></li>
<li><a href="#toc-le-temps-de-listing">Le temps de listing</a></li>
<li><a href="#toc-le-temps-de-dumping">Le temps de dumping</a></li>
<li><a href="#toc-mount">Mount</a></li>
</ul>
</li>
<li><a href="#toc-utilisation-m%C3%A9moire">Utilisation mémoire</a></li>
</ul>
</li>
<li><a href="#toc-conclusion">Conclusion</a></li>
</ul>
<p>Dans cette dépêche on présente Jubako, un méta-format de conteneur et la bibliothèque associée pour lire et écrire ce format, ainsi qu’Arx, un outil se basant sur Jubako pour faire des archives de fichiers, un peu comme tar mais <s>en mieux</s> différemment. La partie Jubako peut être un peu longue, si vous êtes plus intéressé par la finalité du Jubako, vous pouvez directement sauter à <a href="#toc-loutil-arx">la partie Arx</a> pour voir l’usage qui en est fait.</p>
<h2 id="toc-un-peu-de-contexte">Un peu de contexte</h2>
<p>Mon métier, c’est développeur logiciel, en tant qu’indépendant.<br>
Mon client principal depuis six ans, c’est la fondation Kiwix pour qui je maintiens les outils de base de Kiwix, c’est-à-dire les outils bas niveau en C++ pour lire et créer les archives Zim (pour ce qui nous concerne ici). <br>
Les <a href="https://wiki.openzim.org/wiki/ZIM_file_format">archives Zim</a> sont des archives de « contenu » qui pourraient s’apparenter à des zip, mais avec un format interne qui permet une meilleure compression tout en permettant un accès en lecture quasiment en <em>random access.</em><br>
Le format ZIM fonctionne bien, mais il souffre de quelques erreurs de jeunesse. À la base, ZIM c’est « Zeno IMproved », et Zeno… je sais pas trop d’où ça vient. Il y a bien <a href="https://sourceforge.net/p/tntzenoreader">tntzenoreader</a> qui date de 2007. Mais s’il lit les fichiers Zeno, ce n’est pas lui a priori qui crée le format. (Soit dit en passant, c’est probablement la source de libzim vu que je reconnais pas mal de similitudes de code entre les deux projets). De mémoire, Zeno était associé à l’époque où la fondation Wikimedia parlait de mettre Wikipedia sur CD-ROM.</p>
<p>Enfin bon voilà, un peu de dette technique certes, mais surtout un format très orienté pour le cas d’usage de stocker des pages web. Par exemple, chaque entrée a obligatoirement une url, un titre et un mimetype.</p>
<p>Et puis un jour, celui qu’on ne nomme plus arriva avec son confinement généralisé. Durant cette période, j’ai commencé à travailler sur un nouveau format d’archive, inspiré du format ZIM mais avec comme objectif d’en faire un format généraliste qui pourrait être utilisé par d’autres projets.</p>
<p>Ainsi est né doucement le projet Jubako.</p>
<h2 id="toc-le-format-jubako">Le format Jubako</h2>
<p>Le format Jubako est donc un format (binaire) de fichiers pour des conteneurs. </p>
<p>Jubako est un meta-format. Comme XML, il ne définit pas la structure de données à stocker. Ce sera donc au « Vendeur » (qui utilise Jubako dans son projet) de définir la façon dont les données seront stockées. Il est conçu avec le cas d’usage suivant : un conteneur « read-only » créé une fois et distribué à un ensemble d’utilisateurs qui vont lire le conteneur. La lecture du conteneur doit pouvoir se faire sur des machines de relativement faible puissance et en temps « quasi » constant sans décompression préalable. À l’inverse, il est attendu que la machine sur laquelle est fait le conteneur soit un peu plus puissante (ou tout du moins, qu’il soit accepté que la création prenne plus de temps).</p>
<p>Un conteneur Jubako est composé de plusieurs sous-parties appelées pack :</p>
<ul>
<li>Les <code>contentPack</code>s, qui contiennent les données proprement dites. Les <code>contentPack</code>s sont les plus gros en taille et contiennent les données « brutes », sans métadonnées. C’est un peu un conteneur de blob si on reprend la terminologie de git.</li>
<li>Le <code>directoryPack</code> qui lui contient les entrées et métadonnées associées. C’est le pack le plus complexe et le plus « configurable ». Globalement, il stocke des entrées (<code>Entry</code>). Chaque entrée étant composée de métadonnées et pouvant pointer vers un, plusieurs ou aucun contenu (stocké dans les <code>contentPack</code>s).</li>
<li>Le <code>manifestPack</code> qui relie tous ces différents packs ensemble pour former un tout cohérent.</li>
</ul>
<p>Un conteneur Jubako est donc obligatoirement composé d’un <code>manifestPack</code> et d’un <code>directoryPack</code> et d’un ou plusieurs <code>contentPack</code>s (parfois aucun). Les packs peuvent être stockés séparément (sous forme de fichiers dans un dossier par exemple) ou concaténés ensemble pour ne former qu’un seul fichier.</p>
<p>Notez que si un conteneur est logiquement composé de plusieurs contentPack, il est normal que certains contentPack puissent être manquants lors de la lecture. Cela permet d’avoir un système d’extension de conteneur.<br>
Par exemple, pour un packaging d’application, l’application elle-même pourrait être stockée dans un contentPack toujours présent mais les traductions dans différentes langues serait stockées dans des packs distincts. Le conteneur Jubako référence toutes les entrées (et donc toutes les traductions) mais un utilisateur peut avoir en local un conteneur qui contient seulement le contentPack « application » et la traduction dans sa langue.<br>
Ou encore, le projet kiwix pourrait créer des archives avec les images dans des packs séparés, l’utilisateur téléchargerait des archives « sans » images. Et lorsqu’il a une bonne connexion, télécharge les packs manquants.</p>
<p>Bien sûr, c’est au vendeur de faire en sorte que son application sache quoi faire si un pack est manquant (planter, afficher un joli message d’erreur, proposer à l’utilisateur de télécharger le pack…)</p>
<p>Pour ce qui est des entrées stockées dans le directoryPack, c’est là aussi au vendeur de les définir. Le format des entrées est fixe pour chaque cas d’usage (ou alors il vous faudra gérer de la compatibilité entre les versions).<br>
Pour permettre à Jubako (le lecteur, pas le format) de lire le conteneur, le format des entrées est stocké dans le conteneur lui-même.<br>
Le schéma de données suit le principe suivant :</p>
<ul>
<li>Plusieurs types d’entrées peuvent être stockés dans un seul conteneur. Elles sont stockées (et peuvent être récupérées) séparément. Cela permet par exemple de séparer les données selon leur signification dans le conteneur. Par exemple, les fichiers stockés dans une archive de fichier versus les métadonnées de cette même archive (auteur, date de création…). </li>
<li>Un type d’entrée est composé d’un ou plusieurs variants. C’est l’équivalent d’une union pour celles et ceux qui font du c/c++. Par exemple, le type des entrées dans une archive de fichier sera composée de trois variants <code>Fichier</code>, <code>Dossier</code>, <code>Lien</code>.</li>
<li>Chaque variant est composé d’un ensemble d’attributs (l’équivalent d’un struct en c/c++). Chaque attribut a un type défini (entier signé, non signé, tableau de données (de taille fixe ou non), identifiant de contenu), ce qui permet à Jubako de savoir comment lire ces attributs.
Vous noterez que l’identifiant de contenu n’est qu’un attribut parmi d’autres. Une entrée peut donc pointer sur plusieurs contenus, ou aucun.</li>
</ul>
<p>Chaque variant a sa propre structure, mais il est tout de même conseillé d’avoir des attributs communs entre les variants pour pouvoir faire de la recherche d’entrées basée sur ces attributs.</p>
<p>Toutes les entrées d’un même type sont stockées ensemble dans un sous conteneur (tableau) appelé <code>EntryStore</code>. Comme toutes les entrées ont la même taille, les attributs de taille variable sont déportés dans un <code>ValueStore</code>.<br>
Enfin, des index permettent de pointer sur un sous-ensemble d’entrées dans un <code>EntryStore</code> en particulier. Ces index sont nommés et sont les points d’entrées pour la lecture des conteneurs.<br>
Une application va identifier l’index dont elle a besoin et va « suivre » le fil de la structure de donnée pour lire les entrées et accéder au contenu.</p>
<p>Il y a encore pas mal de choses spécifiées (plus ou moins) telles que des redirections ou des entrées qui étendent (rajoutent des attributs) à d’autres entrées. Mais d’une part, cette présentation est déjà bien trop longue et d’autre part, c’est pas encore implémenté, donc on verra plus tard si vous le voulez bien.</p>
<h2 id="toc-la-bibliothèque-jubako">La bibliothèque Jubako</h2>
<p>Il s’agit de l’implémentation de référence (et unique, pour le moment) pour le format Jubako.<br>
Elle est écrite en Rust parce que <s>c’est à la mode</s> c’est un des rares langages (à ma connaissance) qui soit en même temps de bas niveau (comme le C) et qui fournisse aussi des structures de haut niveau dans sa bibliothèque standard (comme le Python). Qui plus est, il fournit un certain nombre de garanties dans sa gestion mémoire qui permet d’avoir une certaine confiance sur un sujet aussi complexe/sensible que de générer/lire des fichiers binaires. (Ça n’empêche pas les bugs, je vous le garantis aussi :) )</p>
<p>(Je me devais de vous dire dans quel langage était écrit Jubako, mais ce n’est pas le plus important. Oui je sais qu’il y a plein de langages de qualité qui auraient pu être utilisés.)</p>
<p>Je ne vais pas trop m’étendre sur cette partie, l’API de la bibliothèque est pas encore sèche et la doc est inexistante pour le moment. Mais voici quand même un petit aperçu de la création et lecture d’un conteneur Jubako :</p>
<p>(Vous noterez une petite incohérence entre le nom des fonctions et des variables/définitions du format. C’est qu’en écrivant cette dépêche, je me suis rendu compte que la terminologie n’était pas bonne. J’ai écrit la dépêche avec une terminologie modifiée mais le code est encore avec « l’ancienne ».)</p>
<pre><code class="rust"><span class="k">use</span><span class="w"> </span><span class="n">jubako</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">jbk</span><span class="p">;</span><span class="w"></span>
<span class="k">use</span><span class="w"> </span><span class="n">jbk</span>::<span class="n">reader</span>::<span class="n">EntryTrait</span><span class="p">;</span><span class="w"></span>
<span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">error</span>::<span class="n">Error</span><span class="p">;</span><span class="w"></span>
<span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">rc</span>::<span class="n">Rc</span><span class="p">;</span><span class="w"></span>
<span class="k">use</span><span class="w"> </span><span class="n">typenum</span>::<span class="p">{</span><span class="n">U31</span><span class="p">,</span><span class="w"> </span><span class="n">U40</span><span class="p">,</span><span class="w"> </span><span class="n">U63</span><span class="p">};</span><span class="w"></span>
<span class="c1">// Cela vous permettra de différencier votre conteneur parmi la multitude de conteneurs jubako qui seront créés (oui, oui, j’y crois)</span>
<span class="k">const</span><span class="w"> </span><span class="n">VENDOR_ID</span>: <span class="kt">u32</span> <span class="o">=</span><span class="w"> </span><span class="mh">0x01_02_03_04</span><span class="p">;</span><span class="w"></span>
<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span>-> <span class="nb">Result</span><span class="o"><</span><span class="p">(),</span><span class="w"> </span><span class="nb">Box</span><span class="o"><</span><span class="n">dyn</span><span class="w"> </span><span class="n">Error</span><span class="o">>></span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">content_pack</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">ContentPackCreator</span>::<span class="n">new</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="s">"test.jbkc"</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">Id</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span><span class="w"> </span><span class="c1">// L’id du pack tel que référencé dans le reste du conteneur</span>
<span class="w"> </span><span class="n">VENDOR_ID</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">FreeData</span>::<span class="o"><</span><span class="n">U40</span><span class="o">></span>::<span class="n">clone_from_slice</span><span class="p">(</span><span class="o">&</span><span class="p">[</span><span class="mh">0x00</span><span class="p">;</span><span class="w"> </span><span class="mi">40</span><span class="p">]),</span><span class="w"> </span><span class="c1">// Mettez ce que vous voulez, c’est pour vous</span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">CompressionType</span>::<span class="n">Zstd</span><span class="p">,</span><span class="w"> </span><span class="c1">// L’algo de compression à utiliser</span>
<span class="w"> </span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">content_pack</span><span class="p">.</span><span class="n">start</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">directory_pack</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">DirectoryPackCreator</span>::<span class="n">new</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="s">"test.jbkd"</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">Id</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span><span class="w"></span>
<span class="w"> </span><span class="n">VENDOR_ID</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">FreeData</span>::<span class="o"><</span><span class="n">U31</span><span class="o">></span>::<span class="n">clone_from_slice</span><span class="p">(</span><span class="o">&</span><span class="p">[</span><span class="mh">0x00</span><span class="p">;</span><span class="w"> </span><span class="mi">31</span><span class="p">]),</span><span class="w"></span>
<span class="w"> </span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="c1">// Les entrées ont une taille fixe. Donc pour les valeurs de taille variable (chaînes de caractères), il nous faut un stockage particulier</span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">value_store</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">directory_pack</span><span class="p">.</span><span class="n">create_key_store</span><span class="p">(</span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">KeyStoreKind</span>::<span class="n">Plain</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="c1">// On definit une entrée composée de deux variants</span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">entry_def</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">Entry</span>::<span class="n">new</span><span class="p">(</span><span class="n">vec</span><span class="o">!</span><span class="p">[</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">Variant</span>::<span class="n">new</span><span class="p">(</span><span class="n">vec</span><span class="o">!</span><span class="p">[</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">Key</span>::<span class="n">PString</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">Rc</span>::<span class="n">clone</span><span class="p">(</span><span class="o">&</span><span class="n">value_store</span><span class="p">)),</span><span class="w"> </span><span class="c1">// Une chaîne de caractères, à stocker dans value_store</span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">Key</span>::<span class="n">new_int</span><span class="p">(),</span><span class="w"> </span><span class="c1">// Un entier</span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">Key</span>::<span class="n">ContentAddress</span><span class="p">,</span><span class="w"> </span><span class="c1">// Un "pointeur" sur du contenu.</span>
<span class="w"> </span><span class="p">]),</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">Variant</span>::<span class="n">new</span><span class="p">(</span><span class="n">vec</span><span class="o">!</span><span class="p">[</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">Key</span>::<span class="n">PString</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">Rc</span>::<span class="n">clone</span><span class="p">(</span><span class="o">&</span><span class="n">value_store</span><span class="p">)),</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">Key</span>::<span class="n">new_int</span><span class="p">(),</span><span class="w"> </span><span class="c1">//</span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">Key</span>::<span class="n">new_int</span><span class="p">(),</span><span class="w"> </span><span class="c1">//</span>
<span class="w"> </span><span class="p">]),</span><span class="w"></span>
<span class="w"> </span><span class="p">]);</span><span class="w"></span>
<span class="w"> </span><span class="c1">// Le store qui contiendra nos entrées.</span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">entry_store_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">directory_pack</span><span class="p">.</span><span class="n">create_entry_store</span><span class="p">(</span><span class="n">entry_def</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">entry_store</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">directory_pack</span><span class="p">.</span><span class="n">get_entry_store</span><span class="p">(</span><span class="n">entry_store_id</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="c1">// On ajoute le contenu de notre entrée :</span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">content</span>: <span class="nb">Vec</span><span class="o"><</span><span class="kt">u8</span><span class="o">></span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"Du super contenu de qualité pour notre conteneur de test"</span><span class="p">.</span><span class="n">into</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">reader</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">BufStream</span>::<span class="n">new</span><span class="p">(</span><span class="n">content</span><span class="p">,</span><span class="w"> </span><span class="n">jbk</span>::<span class="n">End</span>::<span class="nb">None</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">content_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">content_pack</span><span class="p">.</span><span class="n">add_content</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="n">reader</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">entry_store</span><span class="p">.</span><span class="n">add_entry</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="c1">// On utilise le variant 0</span>
<span class="w"> </span><span class="n">vec</span><span class="o">!</span><span class="p">[</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">Value</span>::<span class="n">Array</span><span class="p">(</span><span class="s">"Super"</span><span class="p">.</span><span class="n">into</span><span class="p">()),</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">Value</span>::<span class="n">Unsigned</span><span class="p">(</span><span class="mi">50</span><span class="p">),</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">Value</span>::<span class="n">Content</span><span class="p">(</span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">Content</span>::<span class="n">from</span><span class="p">((</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">Id</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span><span class="w"> </span><span class="c1">// L'id de notre pack</span>
<span class="w"> </span><span class="n">content_id</span><span class="p">,</span><span class="w"> </span><span class="c1">// L'id du contenu dans le pack</span>
<span class="w"> </span><span class="p">))),</span><span class="w"></span>
<span class="w"> </span><span class="p">],</span><span class="w"></span>
<span class="w"> </span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">entry_store</span><span class="p">.</span><span class="n">add_entry</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="c1">// On utilise le variant 1</span>
<span class="w"> </span><span class="n">vec</span><span class="o">!</span><span class="p">[</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">Value</span>::<span class="n">Array</span><span class="p">(</span><span class="s">"Mega"</span><span class="p">.</span><span class="n">into</span><span class="p">()),</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">Value</span>::<span class="n">Unsigned</span><span class="p">(</span><span class="mi">42</span><span class="p">),</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">Value</span>::<span class="n">Unsigned</span><span class="p">(</span><span class="mi">5</span><span class="p">),</span><span class="w"></span>
<span class="w"> </span><span class="p">],</span><span class="w"></span>
<span class="w"> </span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">entry_store</span><span class="p">.</span><span class="n">add_entry</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="c1">// On utilise le variant 1</span>
<span class="w"> </span><span class="n">vec</span><span class="o">!</span><span class="p">[</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">Value</span>::<span class="n">Array</span><span class="p">(</span><span class="s">"Hyper"</span><span class="p">.</span><span class="n">into</span><span class="p">()),</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">Value</span>::<span class="n">Unsigned</span><span class="p">(</span><span class="mi">45</span><span class="p">),</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">Value</span>::<span class="n">Unsigned</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span><span class="w"></span>
<span class="w"> </span><span class="p">],</span><span class="w"></span>
<span class="w"> </span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="c1">// On créé un index qui nous permettra de retrouver nos entrées.</span>
<span class="w"> </span><span class="n">directory_pack</span><span class="p">.</span><span class="n">create_index</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="s">"mon petit index a moi"</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">jubako</span>::<span class="n">ContentAddress</span>::<span class="n">new</span><span class="p">(</span><span class="mf">0.</span><span class="n">into</span><span class="p">(),</span><span class="w"> </span><span class="mf">0.</span><span class="n">into</span><span class="p">()),</span><span class="w"> </span><span class="c1">// Un pointeur vers du contenu qui peut servir à stocker ce que vous voulez. (Rien en l’occurrence ici)</span>
<span class="w"> </span><span class="mf">0.</span><span class="n">into</span><span class="p">(),</span><span class="w"> </span><span class="c1">// Notre index n'est pas trié</span>
<span class="w"> </span><span class="n">entry_store_id</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">jubako</span>::<span class="n">Count</span><span class="p">(</span><span class="mi">3</span><span class="p">),</span><span class="w"> </span><span class="c1">// On a trois entrées</span>
<span class="w"> </span><span class="n">jubako</span>::<span class="n">Idx</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span><span class="w"> </span><span class="c1">// Et on commence à l'offset 0 dans le entry_store.</span>
<span class="w"> </span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">directory_pack_info</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">directory_pack</span><span class="p">.</span><span class="n">finalize</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">content_pack_info</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">content_pack</span><span class="p">.</span><span class="n">finalize</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">manifest_creator</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">jbk</span>::<span class="n">creator</span>::<span class="n">ManifestPackCreator</span>::<span class="n">new</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="s">"test.jbkm"</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">VENDOR_ID</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">FreeData</span>::<span class="o"><</span><span class="n">U63</span><span class="o">></span>::<span class="n">clone_from_slice</span><span class="p">(</span><span class="o">&</span><span class="p">[</span><span class="mh">0x00</span><span class="p">;</span><span class="w"> </span><span class="mi">63</span><span class="p">]),</span><span class="w"></span>
<span class="w"> </span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">manifest_creator</span><span class="p">.</span><span class="n">add_pack</span><span class="p">(</span><span class="n">directory_pack_info</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">manifest_creator</span><span class="p">.</span><span class="n">add_pack</span><span class="p">(</span><span class="n">content_pack_info</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">manifest_creator</span><span class="p">.</span><span class="n">finalize</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="c1">// Vous avez maintenant 3 fichiers "test.jbkm", "test.jbkc" et "test.jbkd".</span>
<span class="w"> </span><span class="c1">// N'en faisons qu'un seul</span>
<span class="w"> </span><span class="n">jbk</span>::<span class="n">concat</span><span class="p">(</span><span class="o">&</span><span class="p">[</span><span class="s">"test.jbkm"</span><span class="p">,</span><span class="w"> </span><span class="s">"test.jbkc"</span><span class="p">,</span><span class="w"> </span><span class="s">"test.jbkd"</span><span class="p">],</span><span class="w"> </span><span class="s">"test.jbk"</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="c1">// On a maintenant un 4ème fichier "test.jbk" qui contient les trois autres.</span>
<span class="w"> </span><span class="c1">// Un peu de lecture</span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">container</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">jbk</span>::<span class="n">reader</span>::<span class="n">Container</span>::<span class="n">new</span><span class="p">(</span><span class="s">"test.jbkm"</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w"> </span><span class="c1">// ou "test.jbkm"</span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">directory</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">container</span><span class="p">.</span><span class="n">get_directory_pack</span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">index</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">directory</span><span class="p">.</span><span class="n">get_index_from_name</span><span class="p">(</span><span class="s">"mon petit index a moi"</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">resolver</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">directory</span><span class="p">.</span><span class="n">get_resolver</span><span class="p">();</span><span class="w"> </span><span class="c1">// C'est nécessaire pour retrouver les infos dans value_store</span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">finder</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">index</span><span class="p">.</span><span class="n">get_finder</span><span class="p">(</span><span class="n">Rc</span>::<span class="n">clone</span><span class="p">(</span><span class="o">&</span><span class="n">resolver</span><span class="p">));</span><span class="w"> </span><span class="c1">// On va enfin pouvoir lire nos données.</span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">entry</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">finder</span><span class="p">.</span><span class="n">get_entry</span><span class="p">(</span><span class="n">jbk</span>::<span class="n">Idx</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span><span class="o">?</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">assert_eq</span><span class="o">!</span><span class="p">(</span><span class="n">entry</span><span class="p">.</span><span class="n">get_variant_id</span><span class="p">(),</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span><span class="w"> </span><span class="c1">// On a bien le variant 0</span>
<span class="w"> </span><span class="n">assert_eq</span><span class="o">!</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="n">resolver</span><span class="p">.</span><span class="n">resolve_to_vec</span><span class="p">(</span><span class="o">&</span><span class="n">entry</span><span class="p">.</span><span class="n">get_value</span><span class="p">(</span><span class="mf">0.</span><span class="n">into</span><span class="p">())</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nb">Vec</span>::<span class="n">from</span><span class="p">(</span><span class="s">"Super"</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">assert_eq</span><span class="o">!</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="n">resolver</span><span class="p">.</span><span class="n">resolve_to_unsigned</span><span class="p">(</span><span class="o">&</span><span class="n">entry</span><span class="p">.</span><span class="n">get_value</span><span class="p">(</span><span class="mf">1.</span><span class="n">into</span><span class="p">())</span><span class="o">?</span><span class="p">),</span><span class="w"></span>
<span class="w"> </span><span class="mi">50</span><span class="w"></span>
<span class="w"> </span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">value_2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">entry</span><span class="p">.</span><span class="n">get_value</span><span class="p">(</span><span class="mf">2.</span><span class="n">into</span><span class="p">())</span><span class="o">?</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">content_address</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">resolver</span><span class="p">.</span><span class="n">resolve_to_content</span><span class="p">(</span><span class="o">&</span><span class="n">value_2</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="c1">// On affiche le contenu sur la sortie standard</span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">reader</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">container</span><span class="p">.</span><span class="n">get_reader</span><span class="p">(</span><span class="n">content_address</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">std</span>::<span class="n">io</span>::<span class="n">copy</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="n">reader</span><span class="p">.</span><span class="n">create_stream_all</span><span class="p">(),</span><span class="w"></span>
<span class="w"> </span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="n">std</span>::<span class="n">io</span>::<span class="n">stdout</span><span class="p">().</span><span class="n">lock</span><span class="p">(),</span><span class="w"></span>
<span class="w"> </span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">entry</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">finder</span><span class="p">.</span><span class="n">get_entry</span><span class="p">(</span><span class="n">jbk</span>::<span class="n">Idx</span><span class="p">(</span><span class="mi">1</span><span class="p">))</span><span class="o">?</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">assert_eq</span><span class="o">!</span><span class="p">(</span><span class="n">entry</span><span class="p">.</span><span class="n">get_variant_id</span><span class="p">(),</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"> </span><span class="c1">// On a bien le variant 1</span>
<span class="w"> </span><span class="n">assert_eq</span><span class="o">!</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="n">resolver</span><span class="p">.</span><span class="n">resolve_to_vec</span><span class="p">(</span><span class="o">&</span><span class="n">entry</span><span class="p">.</span><span class="n">get_value</span><span class="p">(</span><span class="mf">0.</span><span class="n">into</span><span class="p">())</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nb">Vec</span>::<span class="n">from</span><span class="p">(</span><span class="s">"Mega"</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">assert_eq</span><span class="o">!</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="n">resolver</span><span class="p">.</span><span class="n">resolve_to_unsigned</span><span class="p">(</span><span class="o">&</span><span class="n">entry</span><span class="p">.</span><span class="n">get_value</span><span class="p">(</span><span class="mf">1.</span><span class="n">into</span><span class="p">())</span><span class="o">?</span><span class="p">),</span><span class="w"></span>
<span class="w"> </span><span class="mi">42</span><span class="w"></span>
<span class="w"> </span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">assert_eq</span><span class="o">!</span><span class="p">(</span><span class="n">resolver</span><span class="p">.</span><span class="n">resolve_to_unsigned</span><span class="p">(</span><span class="o">&</span><span class="n">entry</span><span class="p">.</span><span class="n">get_value</span><span class="p">(</span><span class="mf">2.</span><span class="n">into</span><span class="p">())</span><span class="o">?</span><span class="p">),</span><span class="w"> </span><span class="mi">5</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">entry</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">finder</span><span class="p">.</span><span class="n">get_entry</span><span class="p">(</span><span class="n">jbk</span>::<span class="n">Idx</span><span class="p">(</span><span class="mi">2</span><span class="p">))</span><span class="o">?</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">assert_eq</span><span class="o">!</span><span class="p">(</span><span class="n">entry</span><span class="p">.</span><span class="n">get_variant_id</span><span class="p">(),</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"> </span><span class="c1">// On a bien le variant 1</span>
<span class="w"> </span><span class="n">assert_eq</span><span class="o">!</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="n">resolver</span><span class="p">.</span><span class="n">resolve_to_vec</span><span class="p">(</span><span class="o">&</span><span class="n">entry</span><span class="p">.</span><span class="n">get_value</span><span class="p">(</span><span class="mf">0.</span><span class="n">into</span><span class="p">())</span><span class="o">?</span><span class="p">)</span><span class="o">?</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nb">Vec</span>::<span class="n">from</span><span class="p">(</span><span class="s">"Hyper"</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">assert_eq</span><span class="o">!</span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="n">resolver</span><span class="p">.</span><span class="n">resolve_to_unsigned</span><span class="p">(</span><span class="o">&</span><span class="n">entry</span><span class="p">.</span><span class="n">get_value</span><span class="p">(</span><span class="mf">1.</span><span class="n">into</span><span class="p">())</span><span class="o">?</span><span class="p">),</span><span class="w"></span>
<span class="w"> </span><span class="mi">45</span><span class="w"></span>
<span class="w"> </span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">assert_eq</span><span class="o">!</span><span class="p">(</span><span class="n">resolver</span><span class="p">.</span><span class="n">resolve_to_unsigned</span><span class="p">(</span><span class="o">&</span><span class="n">entry</span><span class="p">.</span><span class="n">get_value</span><span class="p">(</span><span class="mf">2.</span><span class="n">into</span><span class="p">())</span><span class="o">?</span><span class="p">),</span><span class="w"> </span><span class="mi">2</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="nb">Ok</span><span class="p">(())</span><span class="w"></span>
<span class="p">}</span><span class="w"></span></code></pre>
<h2 id="toc-loutil-arx">L’outil Arx</h2>
<blockquote>
<blockquote>
<p>Jubako c’est beau, mais franchement une lib… t’as pas mieux ? Un vrai cas d’usage ?</p>
</blockquote>
<p>Si ! Et c’est Arx, un outil pour faire des archives de fichiers un peu comme Tar ou Zip. Et en plus, ça sert de démonstrateur pour Jubako.</p>
</blockquote>
<h3 id="toc-tar">Tar</h3>
<p>Petite digression sur tar. Surtout si vous ne savez pas comment est structurée une archive tar.<br>
Tar c’est vieux, très vieux (1979). Ça date d’une époque où les disquettes 3.5 étaient une révolution (elles apparaissent en 1982)</p>
<p>Une archive tar, c’est des entrées (header + contenu) mises bout à bout. C’est tout.<br>
Un tar.gz, c’est un tar compressé avec gzip. Voilà.</p>
<p>Un tar ça marche bien pour du « streaming ». On crée l’archive simplement en parcourant le dossier à archiver et écrivant les entrées dans un « flux » (la sortie standard par exemple) dès qu’on les lit. On passe le flux à gzip et voilà.<br>
Pour décompresser on fait l’inverse.<br>
Et, comme on compresse toute l’archive « par l’extérieur », c’est probablement là qu’on a les meilleurs ratios de compression.<br>
Par contre… accéder à une entrée en particulier… Ben il faut parcourir toute l’archive pour trouver l’entrée. Et pour parcourir toute l’archive, il faut la décompresser. Et ça prend du temps.</p>
<h3 id="toc-le-format-arx"> Le format Arx</h3>
<p>Il n’y a qu’un seul type d’entrée dans Arx et il est composé de trois variants : </p>
<ul>
<li>Fichier</li>
<li>Dossier</li>
<li>Lien symbolique</li>
</ul>
<p>Pour le moment, aucune méta-donnée sur les fichiers n’est stockée. Donc pas de owner, group, droit d’accès ou attributs étendus. Il vous faudra attendre un peu pour ça :) ARX utilise une structure en arbre. Chaque dossier pointe vers un « range » d’entrées qu’il contient. Chaque entrée (y compris les dossiers) contient l’id de son dossier parent. Le nom des entrées est le « basename ». On ne stocke pas tout le chemin de l’entrée.</p>
<p>Cette structure en arbre permet d’accélérer la recherche d’entrée puisqu’on n’a pas besoin de faire une recherche « linéaire » sur toutes les entrées. Cela permet aussi de gagner de la place puisqu’on ne stocke pas le chemin complet. En contrepartie, trouver le chemin complet à partir d’une entrée nécessite de remonter tous ses parents. Mais c’est un cas de figure assez rare.</p>
<p>L’outil <code>arx</code> est relativement simple et permet cinq opérations :</p>
<ol>
<li>créer une archive à partir d’un ou plusieurs dossiers/fichiers,</li>
<li>extraire une archive dans un dossier,</li>
<li>lister les entrées dans une archive,</li>
<li>dumper (j’ai pas de traduction française) une entrée d’une archive,</li>
<li>monter l’archive dans un point de montage.</li>
</ol>
<p>Le code d’arx est assez simple (pour le moment). Il y a sept fichiers qui ne dépassent pas les 500 lignes de code chacun. Je vous invite vivement à aller le voir.</p>
<h3 id="toc-un-peu-de-comparaison">Un peu de comparaison</h3>
<blockquote>
<p>Mais du coup, arx, ça vaut quoi par rapport à tar ?</p>
</blockquote>
<p>Faisons donc un peu de tests. Pour tester arx, j’ai utilisé les sources du kernel Linux (on est sur linuxfr ou pas ?). J’en ai fait trois cas de test différents:</p>
<ul>
<li>Les sources au complet</li>
<li>Le dossier <code>Documentation</code> seulement</li>
<li>Le dossier <code>drivers</code> seulement</li>
</ul>
<p>De plus, arx utilise <a href="https://fr.wikipedia.org/wiki/Zstandard">zstd</a> comme algo de compression. Donc pour éviter de comparer des pommes avec des poires, il faut comparer à un tar.zst, pas un tar.gz. Il y a bien une option chez tar pour compresser en utilisant zstd mais ça utilise pas la même config (niveau de compression) que arx, qui prend le parti de compresser au maximum au détriment du temps de compression. Du coup, l’archive tar.zst est faite avec : <code>tar c linux-5.19 | zstd -19 -T8 -o linux.tar.zst</code>. (niveau de compression 19, 8 threads).<br>
Enfin, pour le contexte de test, les sources à compresser sont sur un SSD mais tout le reste c’est du tmpfs. Ce qui limite les entrées/sorties au minimum (mais en vrai ça change pas les ordres de grandeurs).</p>
<p>Voici les chiffres bruts, l’analyse arrive après :</p>
<h4 id="toc-pour-la-partie-documentation-seulement-9194-entrées">Pour la partie documentation seulement (9194 entrées) :</h4>
<table>
<thead>
<tr>
<th></th>
<th>Taille</th>
<th>Création</th>
<th>Extraction</th>
<th>Listing</th>
<th>Dump</th>
<th>Dump / entry</th>
<th>Mount diff</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Source</strong></td>
<td>58 MB</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>66ms</td>
</tr>
<tr>
<td><strong>Tar zstd</strong></td>
<td>7.8 MB</td>
<td>8s3</td>
<td>68ms</td>
<td>51ms</td>
<td>2m9s</td>
<td>43ms</td>
<td>2m38s</td>
</tr>
<tr>
<td><strong>Arx</strong></td>
<td>8.3 MB</td>
<td>8s7</td>
<td>100ms</td>
<td>5ms</td>
<td>8s9</td>
<td>3.4ms</td>
<td>324ms</td>
</tr>
<tr>
<td><strong><em>Ratios</em></strong></td>
<td><strong><em>1.06</em></strong></td>
<td><strong><em>1.05</em></strong></td>
<td><strong><em>1.47</em></strong></td>
<td><strong><em>0.1</em></strong></td>
<td><strong><em>0.07</em></strong></td>
<td></td>
<td><strong><em>0.002</em></strong></td>
</tr>
</tbody>
</table>
<h4 id="toc-pour-la-partie-drivers-seulement-33056-entrées">Pour la partie drivers seulement (33056 entrées) :</h4>
<table>
<thead>
<tr>
<th></th>
<th>Taille</th>
<th>Création</th>
<th>Extraction</th>
<th>Listing</th>
<th>Dump</th>
<th>Dump / entry</th>
<th>Mount diff</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Source</strong></td>
<td>865 MB</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>490ms</td>
</tr>
<tr>
<td><strong>Tar zstd</strong></td>
<td>73 MB</td>
<td>1m7</td>
<td>688ms</td>
<td>570ms</td>
<td>1h36</td>
<td>520ms</td>
<td>2h41m</td>
</tr>
<tr>
<td><strong>Arx</strong></td>
<td>80 MB</td>
<td>3m25</td>
<td>930ms</td>
<td>19ms</td>
<td>35s</td>
<td>3.1ms</td>
<td>1s75</td>
</tr>
<tr>
<td><strong><em>Ratios</em></strong></td>
<td><strong><em>1.09</em></strong></td>
<td><strong><em>3</em></strong></td>
<td><strong><em>1.35</em></strong></td>
<td><strong><em>0.03</em></strong></td>
<td><strong><em>0.006</em></strong></td>
<td></td>
<td><strong><em>0.00018</em></strong></td>
</tr>
</tbody>
</table>
<h4 id="toc-et-pour-les-sources-complètes-81958-entrées">Et pour les sources complètes (81958 entrées) :</h4>
<table>
<thead>
<tr>
<th></th>
<th>Taille</th>
<th>Création</th>
<th>Extraction</th>
<th>Listing</th>
<th>Dump</th>
<th>Dump / entry</th>
<th>Mount diff</th>
<th>Compilation</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Source</strong></td>
<td>1326 MB</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>880ms</td>
<td>32m</td>
</tr>
<tr>
<td><strong>Tar zstd</strong></td>
<td>129 MB</td>
<td>1m37s</td>
<td>1s130ms</td>
<td>900ms</td>
<td>6h20m</td>
<td>833ms</td>
<td></td>
<td></td>
</tr>
<tr>
<td><strong>Arx</strong></td>
<td>140 MB</td>
<td>4m45s</td>
<td>1s47ms</td>
<td>45ms</td>
<td>1m28s</td>
<td>4ms</td>
<td>4s2</td>
<td>48m</td>
</tr>
<tr>
<td><strong><em>Ratios</em></strong></td>
<td><strong><em>1.08</em></strong></td>
<td><strong><em>2.93</em></strong></td>
<td><strong><em>1.3</em></strong></td>
<td><strong><em>0.05</em></strong></td>
<td><strong><em>0.0045</em></strong></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<h4 id="toc-la-taille">La taille</h4>
<ul>
<li>Les sources décompressées du kernel font 1,3 Go.</li>
<li>L’archive tar.zst fait 129 Mo. (Un ratio de compression de 9,76%).</li>
<li>L’archive arx elle fait 140 Mo. (Un ratio de compression de 10,56%).</li>
</ul>
<p>Arx compresse moins bien. On a environ 8 % d’écart entre les deux archives. On s’y attendait au vu des structures de chaque archive, mais perso je trouve pas ça dégueu. Surtout comparé au 1,3 Go d’origine. Et pour info, le tar.gz utilisé par tout le monde, fait 200 Mo et ça a pas l’air de gêner grand monde alors bon, 140 Mo, ça va.</p>
<h4 id="toc-le-temps-de-création">Le temps de création</h4>
<p>La création de l’archive kernel.tar.zst se fait en 1m37s alors que l’arx se fait en 4m45s. Sans surprise ici, tar est bien plus rapide. On a globalement un rapport de 3 entre les temps de création. C’est en accord avec le cas d’usage de Jubako (temps de création plus lent, mais exploitation plus rapide) mais la création est probablement la partie la moins optimisée pour le moment. Il devrait être possible d’améliorer les perfs du côté de Jubako pour limiter l’écart (notamment compresser les contenus en parallèle).</p>
<h4 id="toc-le-temps-dextraction">Le temps d’extraction</h4>
<p>Le temps d’extraction se fait dans des temps relativement similaires : 1s1 pour tar et 1s5 pour arx. Là aussi, c’est en accord avec la structure des données des deux formats. Tar n’a qu’un seul flux à décompresser. Alors que Jubako doit parcourir les entrées et doit ensuite décompresser plusieurs flux internes (avec tout le temps d’initialisation associé). Mais, là encore, il y a probablement matière à amélioration du côté de Jubako/arx. </p>
<h4 id="toc-le-temps-de-listing">Le temps de listing</h4>
<p>Ici on n’extrait pas le contenu, mais on liste les fichiers dans l’archive. Il faut 10 à 20 fois moins de temps à arx pour lister le contenu de l’archive par rapport à tar. Là aussi, c’est cohérent avec la structure de données des deux formats. Jubako n’a aucun contenu à décompresser et il n’a que le <code>directoryPack</code> à lire, alors que tar doit décompresser toute l’archive.</p>
<p>On commence à toucher à des cas d’usage pour lesquels Jubako a été conçu : accéder aux données sans extraire toute l’archive.</p>
<h4 id="toc-le-temps-de-dumping">Le temps de dumping</h4>
<p>Par dumping j’entends extraire un seul fichier en particulier d’une archive.<br>
Le cas de test est d’extraire un fichier sur trois de l’archive.<br>
Pour le kernel au complet, ça veut dire extraire 27319 fichiers de l’archive (et donc lancer 27319 fois tar/arx)</p>
<p>Il faut 1m30 à arx pour faire le travail. Du côté de tar il faut… 6h20.<br>
Ça fait une moyenne de 4ms par entrée du côté d'arx et 0,8s pour tar.<br>
C’est un ratio de <strong>200</strong> !!</p>
<p>Si on réduit la taille des archives (ce qui limite la quantité de données à décompresser pour tar), le ratio baisse un peu, mais on reste quand même avec arx 12 fois plus rapide que tar pour la documentation. (3064 fichiers à dumper)</p>
<p>On voit ici clairement l’avantage de Jubako sur tar. C’est prévisible, rien de magique, on travaille juste avec un format de fichier fait pour ça, c’est normal que ça dépote.</p>
<p>Cela met aussi en évidence le fait qu’arx met un temps relativement constant pour extraire un fichier, quelle que soit la taille de l’archive.<br>
À l’inverse pour tar, les temps d’extraction augmentent avec la taille des archives.</p>
<h4 id="toc-mount">Mount</h4>
<p>Un mount tout seul ne prend pas de temps, il faut voir quand on veut lire les fichiers. Le test correspond donc à un mount suivi d’un <code>diff -r</code> entre ce qui a été monté et les sources d’origine. C’est le temps de diff qui est mesuré. L’archive tar est montée avec l’outil <code>archivemount</code>.</p>
<p>Bon, là c’est clair, arx est bien bien bien plus rapide que tar : un diff sur une archive arx monté est de <strong>490</strong> à <strong>5500</strong> fois plus rapide qu’un diff sur une archive tar. (Je n’ai pas osé faire le test sur le kernel complet, mais je vous laisse le faire si vous voulez). On notera quand même que le diff prend quatre à cinq fois plus de temps qu’un diff simple entre deux dossiers (sans mount).</p>
<p>Mais diff, c’est un cas vachement particulier, on parcourt certes tous les fichiers, mais c’est assez séquentiel et on y accède qu’une seule fois. Ça donnerait quoi avec un vrai cas d’usage ?</p>
<p>Du coup, compilons un kernel…<br>
La compilation du kernel simplement (configuration par défaut, <code>make -j8</code>, les sources extraites dans le fs, sur sdd) prend 32 minutes sur ma machine. La même compilation mais sur une archive montée (archive elle-même stockée sur le sdd, pas dans tmpfs) prend 48 minutes. Alors oui, ça prend 1,5 fois plus de temps, mais sachez que l’implémentation actuelle de <code>arx mount</code> est mono-threadée, donc le <code>make -j8</code> en prend un coup de base. Mais vous n’avez utilisé que 140 Mo d’espace disque au lieu de 1,3Go pour stocker les sources du kernel.</p>
<h3 id="toc-utilisation-mémoire">Utilisation mémoire</h3>
<p>Niveau utilisation mémoire, Jubako est, normalement, relativement sobre.</p>
<p>La partie index (stockée dans le directoryPack) est directement exploitable par Jubako. Rien n’est compressé et Jubako est conçu pour lire directement les données stockées dans le fichier. Bien sûr, ça engendre beaucoup d’I/O et c’est donc au détriment des performances. Pour réduire ça, différentes stratégies sont utilisées (bufferisation, mmap, cache…). Mais dans un contexte vraiment limité en mémoire, c’est désactivable (sur le principe, il y a pas vraiment d’options aujourd’hui dans l’implémentation). De toute façon, le directoryPack de l’archive de l’ensemble des sources du kernel fait 2 Mo. Donc on pourrait tout mettre en ram sans que ça ne pose de problème.</p>
<p>Au niveau des données compressées, ça nécessite un peu plus de données. Les données sont regroupées en « clusters » et les clusters sont compressés indépendamment. Donc pour accéder à un contenu, il faut décompresser au pire un cluster entier. L’implémentation actuelle crée des clusters de 4 Mo maximum. Donc sans cache, accéder à un contenu couterait 4 Mo max (plus les structures internes utilisées par les algorithmes de (dé)compression).</p>
<p>En pratique, il y a du cache mis en place (et pas obligatoirement de la manière la plus optimisée). Jubako fait de la décompression partielle : il commence à décompresser un cluster jusqu’aux données auxquelles on veut accéder. Mais pour éviter de décompresser à nouveau le début du cluster plus tard, on garde en mémoire le contexte de décompression en mémoire. Donc chaque cluster a certes 4 Mo maximum, mais on garde plus en mémoire. Et actuellement, on a un cache de 20 clusters en mémoire. Donc environ 80 Mo plus les 20 contextes de décompression (et je n’ai pas mesuré leur taille).</p>
<p>Au global, un <code>arx mount</code> pendant une compilation de kernel consomme 310 Mo au maximum (Maximum resident size). Il y a un peu de travail d’implémentation et d’ajustement pour avoir le meilleur compromis mémoire utilisée/performance. Et probablement de la configuration nécessaire pour s’adapter aux différents cas d’usage.</p>
<h2 id="toc-conclusion">Conclusion</h2>
<p>Voilà pour une première présentation de Jubako et Arx.</p>
<p>On est loin d’avoir un produit fini. Les specs de Jubako ne sont pas complètes. L’implémentation n’implémente pas tout ce qui est spécifié (et la spec <s>risque de</s> va changer avec l’implémentation).<br>
La bibliothèque Jubako elle-même est encore très jeune. Elle fonctionne, mais elle n’est probablement pas exempte de bugs, l’api est à améliorer, sans parler des performances.</p>
<p>Pour ce qui est de Arx, là aussi on en est au début. Arx stocke très peu de métadonnées sur les fichiers pour le moment, mais c’est une base et elle sert de très bon démonstrateur pour Jubako.</p>
<p>La différence entre ce qui est perdu (taille de l’archive, temps de compression) et ce qui est gagné (utilisation d’une archive sans la décompresser entièrement) est plus que raisonnable pour moi (surtout pour une première version).</p>
<p>Il y a encore pas mal de choses à faire mais c’est un premier jalon important pour moi de voir un projet imaginé il y a maintenant deux ans prendre forme et arriver à un résultat assez probant. (J’ai d’ailleurs eu du mal à me restreindre à faire une dépêche courte, j’en suis désolé… ou presque).</p>
<p>Jubako et Arx peuvent avoir leur utilité dans des cas d’usage particuliers. Pour ce qui est de la classique archive de fichiers qui sera extraite, il est fort probable que tar reste la référence. Mais Jubako ouvre une porte sur de toutes nouvelles façons de faire. Il serait possible de diffuser du contenu et de le lire <em>sans</em> le décompresser. Imaginez un peu :</p>
<ul>
<li>Une distribution Linux basée sur Jubako pour ses paquets. Des paquets qui ne seraient jamais décompressés mais montés à la demande…</li>
<li>Un système de sauvegarde (une sauvegarde incrémentale ne serait qu’une archive Jubako qui réutilise le contentPack des sauvegardes précédentes)…</li>
<li>Si python savait lire des archives Jubako…</li>
<li>Si on diffusait nos sites web statiques à coup de conteneur Jubako (ou de serveurs autonomes qui contiennent des conteneurs Jubako sous forme de ressources intégrées) …</li>
<li>Si les navigateurs web savaient lire du Jubako et qu’on packageait nos applis JavaScript à coup de Jubako…</li>
</ul>
<p>Comment ça je m’emballe ?!</p>
</div><div><a href="https://linuxfr.org/news/jubako-et-arx-un-conteneur-universel-et-son-format-d-archive.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/129067/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/jubako-et-arx-un-conteneur-universel-et-son-format-d-archive#comments">ouvrir dans le navigateur</a>
</p>
GaMaorfenorYves Bourguignonvmagninpalm123Ysabeau 🧶 🧦patrick_gLtrlgJulien Jorgehttps://linuxfr.org/nodes/129067/comments.atomtag:linuxfr.org,2005:Bookmark/51292022-09-10T22:10:52+02:002022-09-10T22:10:52+02:00Traditional Packaging is not Suitable for Modern Applications<a href="https://theevilskeleton.gitlab.io/2022/08/29/traditional-packaging-is-not-suitable-for-modern-applications.html">https://theevilskeleton.gitlab.io/2022/08/29/traditional-packaging-is-not-suitable-for-modern-applications.html</a> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/128719/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/tisaac/liens/traditional-packaging-is-not-suitable-for-modern-applications#comments">ouvrir dans le navigateur</a>
</p>
tisaachttps://linuxfr.org/nodes/128719/comments.atomtag:linuxfr.org,2005:Diary/403102022-06-29T22:17:35+02:002022-06-29T22:17:35+02:00pkcon rizLicence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<p>Bonjour lecteur,</p>
<p>Je comprend pas pkcon, ça doit être meilleur avec de la bière. </p>
<p>J'utilise KDE Neon et j'en suis super content. j'utilisais apt-get pour installer aptitude et après j'utilisais aptitude et j'étais content. apt-get était un peu mon internet explorer du package linux.</p>
<p>Et puis un jour j'ai remarqué que pkcon était installé sur mon système. Je me suis renseigné et il était dit que c'était l'avenir que pkcon ferait le café. Bref trop bien.<br>
<a href="https://neon.kde.org/faq#command-to-update">https://neon.kde.org/faq#command-to-update</a></p>
<p>J'ai lu le help, le man et quelques pages sur Internet. J'ai profité d'un nouveau PC (d'occasion) pour passer 3 mois a VRAIMENT essayer de n'utiliser que ça.</p>
<p>Et bien franchement je dois dire que j'y comprend rien.<br>
Ça ne trouve aucun paquet. Ça fait pas de proposition en cas d'échec ou alors des proposition moisies. Ça oblige parfois a donner le paquet avec sa version (pour vlc. Comme si vlc était un truc pas mainstream en 2022). Ça semble manquer de plein de paquets. Quand un paquet est déjà installé il te dit qu'il le trouve pas.</p>
<p>Avec pkcon, installer un server ssh nécessite… je sais pas quoi j'ai pas réussi. Probablement de connaître le nom exact du paquet (avec la version).</p>
<p>Avec aptitude, <code>aptitude install ssh</code> et voilà !</p>
<p>Même chose avec uncomplicated firewall.<br>
<code>aptitude install ufw</code> et hop. Sous pkcon, je cherche encore.</p>
<p>Ah si pkcon est parfait pour installer aptitude.<br>
<code>pkcon install aptitude</code> marche comme de rien.</p>
<p>A+</p>
<div><a href="https://linuxfr.org/users/blobmaster/journaux/pkcon-riz.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/128157/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/blobmaster/journaux/pkcon-riz#comments">ouvrir dans le navigateur</a>
</p>
blobmasterhttps://linuxfr.org/nodes/128157/comments.atomtag:linuxfr.org,2005:News/410342022-06-01T18:52:35+02:002022-06-01T18:52:35+02:00Alire, le package manager d'AdaLicence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<div><p>Dans <a href="//linuxfr.org/users/blackknight/journaux/retour-sur-une-annee-d-apprentissage-d-ada-par-un-dev-c">un précédent journal</a>, il m’a été demandé de présenter <a href="https://alire.ada.dev/">Alire</a> sous la forme <a href="//linuxfr.org/users/blackknight/journaux/retour-sur-une-annee-d-apprentissage-d-ada-par-un-dev-c#comment-1887855">d’une dépêche</a>. Voilà, j’ai fini par prendre le temps et j’ai choisi la façon de le présenter.<br>
Je vous propose donc une sorte de pas-à-pas plutôt qu’une explication un peu brutale</p>
<h2 id="toc-le-but">Le but</h2>
<p>Nous allons donc créer des <em>crates Alire</em> (les Rustistes auront reconnu le terme).<br>
J’ai bien dit <em>des</em> car cela va permettre de voir les deux types, <em>lib</em> ou <em>bin</em> que l’on peut créer.</p>
<h2 id="toc-le-projet">Le projet</h2>
<p>Le but n’étant pas d’écrire du code Ada, on va prendre un de mes projets préférés qui n’a, au moment de l’écriture de ces lignes, pas de <em>crate</em> associée.<br>
J’ai nommé le <a href="http://cbsg.sf.net/"><em>Corporate Bullshit Generator</em></a>, logiciel ô combien indispensable, source inépuisable d’études en scalabilité (<a href="https://archive.fosdem.org/2019/schedule/event/ada_distribution/">autopromotion</a>).</p>
<p>Ce magnifique projet est l’œuvre de Gautier de Montmollin qui produit aussi des choses beaucoup plus sérieuses comme <a href="https://unzip-ada.sourceforge.io/">Zip-Ada</a>, une <em>lib</em> pour gérer les archives zip, <a href="https://apdf.sourceforge.io/">Ada PDF Writer</a> ou <a href="https://hacadacompiler.sourceforge.io/">HAC</a>, un compilateur Ada partiel.<br>
Évidemment, tout est codé en pur Ada.</p>
<p>Bon assez causé, on y va direct car c’est NOTRE PROJEEEEETTTT :)</p>
</div><ul><li>lien nᵒ 1 : <a title="https://alire.ada.dev" hreflang="en" href="https://linuxfr.org/redirect/110509">Alire</a></li><li>lien nᵒ 2 : <a title="https://github.com/alire-project/alire/releases" hreflang="en" href="https://linuxfr.org/redirect/110510">Releases d'Alire</a></li><li>lien nᵒ 3 : <a title="http://cbsg.sf.net/" hreflang="en" href="https://linuxfr.org/redirect/110511">Corporate bullshit Generator Live</a></li><li>lien nᵒ 4 : <a title="https://alire.ada.dev/crates.html" hreflang="en" href="https://linuxfr.org/redirect/110524">La liste des crates</a></li></ul><div><h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li>
<a href="#toc-cest-parti-avec-les-pr%C3%A9requis">C’est parti avec les prérequis</a><ul>
<li><a href="#toc-installation-dalire">Installation d’Alire</a></li>
<li><a href="#toc-premiers-pas">Premiers pas</a></li>
<li><a href="#toc-r%C3%A9cup%C3%A9ration-du-code-du-cbsg-sur-sf">Récupération du code du CBSG sur SF</a></li>
</ul>
</li>
<li><a href="#toc-notre-premi%C3%A8re-crate-une-biblioth%C3%A8que">Notre première crate, une bibliothèque</a></li>
<li>
<a href="#toc-cr%C3%A9ation-dun-crate-dexemples">Création d’un crate d’exemples</a><ul>
<li><a href="#toc-edition-du-fichier-toml">Edition du fichier TOML</a></li>
<li><a href="#toc-on-est-en-dev-on-na-rien-publi%C3%A9">On est en dev, on n’a rien publié</a></li>
<li><a href="#toc-on-teste">On teste</a></li>
</ul>
</li>
<li><a href="#toc-conclusion">Conclusion</a></li>
</ul>
<h2 id="toc-cest-parti-avec-les-prérequis">C’est parti avec les prérequis</h2>
<h3 id="toc-installation-dalire">Installation d’Alire</h3>
<p>Je ne vais pas paraphraser totalement <a href="https://alire.ada.dev/docs/#installation">la doc</a> mais il vous faut installer un compilateur Ada sur votre distribution, histoire d’avoir les bibliothèques du langage dans votre système.<br>
Ensuite, on télécharge le binaire et on le met dans son <em>PATH</em> pour être tranquille.<br>
Les courageux pourront construire à partir des sources.</p>
<h3 id="toc-premiers-pas">Premiers pas</h3>
<p>Là, encore, je vais faire plus court que <a href="https://alire.ada.dev/docs/#first-steps">la doc officielle</a>. <br>
On va juste vérifier que notre installation fonctionne bien.</p>
<pre><code>fred@tatooine:~/Dev/Ada$ alr get hello
ⓘ Deploying release hello=1.0.1...
-=O=- # # # #
ⓘ Deploying release libhello=1.0.0...
############################################################################################################################################################ 100,0%
hello=1.0.1 successfully retrieved.
Dependencies were solved as follows:
+ libhello 1.0.0 (new)
</code></pre>
<p>On va ensuite dans le répertoire créé (aujourd’hui, <em>hello_1.0.1_dcc36a2f</em>) et on exécute :</p>
<pre><code>fred@tatooine:~/Dev/Ada$ alr run
Welcome to the toolchain selection assistant
In this assistant you can set up the default toolchain to be used with any crate
that does not specify its own top-level dependency on a version of gnat or
gprbuild.
If you choose "None", Alire will use whatever version is found in the
environment.
ⓘ gnat is currently not configured. (alr will use the version found in the environment.)
Please select the gnat version for use with this configuration
1. gnat_native=11.2.4
2. None
3. gnat_external=2021.0.0 [Detected at /opt/gnat/2021/bin/gnat]
4. gnat_arm_elf=11.2.4
5. gnat_avr_elf=11.2.4
6. gnat_riscv64_elf=11.2.4
7. gnat_arm_elf=11.2.3
8. gnat_native=11.2.3
9. gnat_riscv64_elf=11.2.3
0. gnat_arm_elf=11.2.2
a. (See more choices...)
Enter your choice index (first is default):
> 3
ⓘ Selected tool version gnat_external=2021.0.0
ⓘ Choices for the following tool are narrowed down to releases compatible with just selected gnat_external=2021.0.0
ⓘ gprbuild is currently not configured. (alr will use the version found in the environment.)
Please select the gprbuild version for use with this configuration
1. gprbuild=2021.0.0 [Detected at /opt/gnat/2021/bin/gprbuild]
2. None
Enter your choice index (first is default):
> 1
ⓘ Selected tool version gprbuild=2021.0.0
Setup
[mkdir] object directory for project Libhello
[mkdir] library directory for project Libhello
[mkdir] object directory for project Hello
Compile
[Ada] hello.adb
[Ada] libhello.adb
Build Libraries
[gprlib] hello.lexch
[archive] libhello.a
[index] libhello.a
Bind
[gprbind] hello.bexch
[Ada] hello.ali
Link
[link] hello.adb
Hello, world!
</code></pre>
<p>Mais alors, il s’est passé quoi ?<br>
Normalement, si c’est votre première installation, comme ci-dessus, <em>Alire</em> va vous demander de choisir votre <em>toolchain</em> en fonction de ce qui se trouve dans votre système.<br>
Personnellement, j’ai, entre autres, la version 2021 du compilateur fourni par Adacore dans <em>/opt/gnat</em>.<br>
Ensuite, le binaire n’étant pas encore créé, on passe par un <em>build</em> puis une exécution.</p>
<p>Qu’on se rassure, le processus de choix de la <em>toolchain</em> ne se fait qu’une fois, mais il est possible de changer en cours de route via les commandes <em>alr toolchain</em>.</p>
<p>De manière générale, à l’instar de beaucoup d’autres outils, on peut utiliser l’aide en ligne via <em>alr help</em> comme <em>alr help toolchain</em>.</p>
<p>Maintenant que l’on voit que cela fonctionne, on passe aux choses sérieuses.</p>
<h3 id="toc-récupération-du-code-du-cbsg-sur-sf">Récupération du code du CBSG sur SF</h3>
<p>Le code du <em>Corporate Bullshit Generator</em> (<em>CBSG</em> pour les intimes) est disponible sur Sourceforge et possède un miroir sur Github</p>
<p>On récupère soit via</p>
<pre><code>svn checkout https://svn.code.sf.net/p/cbsg/code/ cbsg-code
</code></pre>
<p>soit via</p>
<pre><code>git clone https://github.com/zertovitch/cbsg.git cbsg-code
</code></pre>
<p>L’un ou l’autre ne pose aucun problème, cela ne servira qu’à piocher dans le code source.</p>
<p>Préparons maintenant notre première <em>crate</em>, une <em>lib</em>.</p>
<h2 id="toc-notre-première-crate-une-bibliothèque">Notre première crate, une bibliothèque</h2>
<p>On commence par créer un patron de <em>crate</em></p>
<pre><code>fred@tatooine:~/Dev/Ada$ alr init --lib cbsg
</code></pre>
<p>Cela donne la hiérarchie suivante:</p>
<pre><code>cbsg
├── alire.toml
├── cbsg.gpr
├── config
│ ├── cbsg_config.ads
│ ├── cbsg_config.gpr
│ └── cbsg_config.h
└── src
└── cbsg.ads
</code></pre>
<p>Quand on analyse le code du <em>Corporate Bullshit Generator</em>, on voit qu’un package fournit la fonctionnalité que l’on veut exposer.<br>
En effet, <em>corporate_bullshit</em> est le package générique donnant les fonctions retournant les phrases tant attendues.</p>
<pre><code class="ada"><span class="kd">generic</span>
<span class="n">Paragraph_Mark</span> <span class="p">:</span> <span class="kt">String</span><span class="p">;</span>
<span class="n">Paragraph_End_Mark</span> <span class="p">:</span> <span class="kt">String</span><span class="p">;</span>
<span class="n">Dialog_Mark</span> <span class="p">:</span> <span class="kt">String</span><span class="p">;</span>
<span class="kd">package</span> <span class="nc">Corporate_Bullshit</span> <span class="kr">is</span>
<span class="kd">function</span> <span class="nf">Sentence</span> <span class="nf">return</span> <span class="nf">String</span><span class="p">;</span>
<span class="kd">function</span> <span class="nf">Workshop</span> <span class="nf">return</span> <span class="nf">String</span><span class="p">;</span>
<span class="kd">function</span> <span class="nf">Short_Workshop</span> <span class="nf">return</span> <span class="nf">String</span><span class="p">;</span>
<span class="kd">function</span> <span class="nf">Short_Meeting</span> <span class="nf">return</span> <span class="nf">String</span><span class="p">;</span>
<span class="kd">function</span> <span class="nf">Financial_Report</span> <span class="nf">return</span> <span class="nf">String</span><span class="p">;</span>
<span class="kr">end</span> <span class="nf">Corporate_Bullshit</span><span class="p">;</span></code></pre>
<p>On incorporera donc le fichier de spécification <em>corporate_bullshit.ads</em> ainsi que le corps du package, <em>corporate_bullshit.adb</em>.</p>
<p>Il manque encore une chose. En regardant le début du fichier <em>corporate_bullshit.adb</em>, on voit deux packages en inclusion, <em>Ada.Characters.Handling</em> et <em>Delirium</em>.</p>
<pre><code class="ada"><span class="kn">with</span> <span class="nn">Ada.Characters.Handling</span><span class="p">;</span> <span class="kn">use</span> <span class="nn">Ada.Characters.Handling</span><span class="p">;</span>
<span class="kn">with</span> <span class="nn">Delirium</span><span class="p">;</span> <span class="kn">use</span> <span class="nn">Delirium</span><span class="p">;</span></code></pre>
<p><a href="http://www.ada-auth.org/standards/rm12_w_tc1/html/RM-A-3-2.html">Ada.Characters.Handling</a> est un package standard Ada permettant la transformation majuscule/minuscule, les tests d’appartenance d’un caractère à une classe (alphanumérique, numérique…) entre autres choses.</p>
<p>Delirium est un package du <em>CBSG</em>. D’après les commentaires, il permet de gérer la grammaire des phrases générées. Ce n’est pas le plus clair des codes que j’ai vu mais ça fonctionne et comme on ne s’en sert pas directement…</p>
<p>Par contre, cela veut dire qu’il doit faire partie de notre <em>lib</em>.</p>
<p>On copie donc les fichiers ad[sb] de <em>delirium</em> et <em>corporate_bullshit</em>.<br>
Finalement, le fichier généré <em>cbsg.ads</em> ne nous servant pas, on le retire.<br>
Au final, on obtient cela :</p>
<pre><code>cbsg
├── alire.toml
├── cbsg.gpr
├── config
│ ├── cbsg_config.ads
│ ├── cbsg_config.gpr
│ └── cbsg_config.h
└── src
├── corporate_bullshit.adb
├── corporate_bullshit.ads
├── delirium.adb
└── delirium.ads
</code></pre>
<p>On vérifie que tout se passe bien avec un petit <em>alr build</em> dans le répertoire</p>
<pre><code>Setup
[mkdir] object directory for project Cbsg
[mkdir] library directory for project Cbsg
Compile
[Ada] delirium.adb
[Ada] corporate_bullshit.adb
Build Libraries
[gprlib] Cbsg.lexch
[archive] libCbsg.a
[index] libCbsg.a
</code></pre>
<p>Pour tester tout ça, on va passer à la deuxième partie, la <em>crate</em> d’exemples.</p>
<h2 id="toc-création-dun-crate-dexemples">Création d’un crate d’exemples</h2>
<p>Maintenant que notre bibliothèque est prête, nous allons créer une <em>crate</em> avec un exemple simple.<br>
Cette fois-ci, on utilisera la commande dans un répertoire au même niveau que le répertoire <em>cbsg</em>. Cela n’a rien d’obligatoire au final mais là, ce sera plus facile mais stop au suspense, on embraye.</p>
<pre><code>fred@tatooine:~/Dev/Ada$ alr init --bin cbsg_examples
</code></pre>
<p>Cela donne la hiérarchie suivante:</p>
<pre><code>cbsg_examples
├── alire
│ └── alire.lock
├── alire.toml
├── cbsg_examples.gpr
├── config
│ └── cbsg_examples_config.gpr
└── src
└── cbsg_examples.adb
</code></pre>
<p>Pour exemple, nous prendrons le plus simple qui soit dans le code du <em>CBSG</em>, <em>produce_corporate_bullshit.adb</em>.</p>
<p>On copie donc ce fichier dans le répertoire <em>src</em>.<br>
Le fichier <em>cbsg_examples.adb</em> ne nous sert pas, on le retire… Sauf que le projet s’attend à ce que l’exécutable de notre <em>crate</em> soit <em>cbsg_examples</em>.</p>
<p>Cela étant déclaré dans le fichier <em>cbsg_examples.gpr</em>, on modifie cela.</p>
<p>Ce fichier est un fichier au format <a href="https://docs.adacore.com/gprbuild-docs/html/gprbuild_ug.html">GPRBuild</a>. <br>
GPRBuild, c’est un outil fourni par Adacore qui est un peu le <em>make</em> sur-vitaminé de GNAT, ce dernier disposant déjà de <em>gnatmake</em>. <br>
La syntaxe se veut très Ada, mais il n’est pas compliqué dans notre cas de modifier celui généré pour changer l’exécutable.</p>
<p>Ainsi, il suffit de trouver la ligne</p>
<pre><code class="ada"><span class="kr">for</span> <span class="n">Main</span> <span class="kn">use</span> <span class="p">(</span><span class="s">"cbsg_examples.adb"</span><span class="p">);</span></code></pre>
<p>et de la transformer en </p>
<pre><code class="ada"><span class="kr">for</span> <span class="n">Main</span> <span class="kn">use</span> <span class="p">(</span><span class="s">"produce_corporate_bullshit.adb"</span><span class="p">);</span></code></pre>
<p>Au final, on obtient l’arbre suivant :</p>
<pre><code>cbsg_examples/
├── alire
│ ├── alire.lock
├── alire.toml
├── cbsg_examples.gpr
├── config
│ ├── cbsg_examples_config.ads
│ ├── cbsg_examples_config.gpr
│ └── cbsg_examples_config.h
└── src
└── produce_corporate_bullshit.adb
</code></pre>
<p>So far so good… sauf que l’on n’a précisé nulle part la dépendance à <em>cbsg</em> !!!</p>
<p>Pour cela, on utilisera la commande</p>
<pre><code>fred@tatoiine:~/Dev/Ada/cbsg_examples$ alr with cbsg
</code></pre>
<p>Dans un cas normal, cela suffirait si la crate <em>cbsg</em> était déjà publiée mais ce n’est pas notre cas.</p>
<h3 id="toc-edition-du-fichier-toml">Edition du fichier TOML</h3>
<p>Le fichier généré par Alire est au format <a href="https://fr.wikipedia.org/wiki/TOML">TOML</a> (pour ceux qui n’auraient pas vu) et contient maintenant ceci:</p>
<pre><code class="toml"><span class="n">name</span> <span class="o">=</span> <span class="s">"cbsg_examples"</span>
<span class="n">description</span> <span class="o">=</span> <span class="s">"Corporate bullshit generator examples"</span>
<span class="n">version</span> <span class="o">=</span> <span class="s">"0.0.1"</span>
<span class="n">authors</span> <span class="o">=</span> <span class="p">[</span><span class="s">"Gautier de Montmollin"</span><span class="p">]</span>
<span class="n">maintainers</span> <span class="o">=</span> <span class="p">[</span><span class="s">"Frédéric Praca <xxxxxxxxxxxxx>"</span><span class="p">]</span>
<span class="n">maintainers-logins</span> <span class="o">=</span> <span class="p">[</span><span class="s">"FredPraca"</span><span class="p">]</span>
<span class="n">executables</span> <span class="o">=</span> <span class="p">[</span><span class="s">"cbsg_examples"</span><span class="p">]</span>
<span class="p">[[</span><span class="n">depends-on</span><span class="p">]]</span> <span class="c1"># Added by alr</span>
<span class="n">cbsg</span> <span class="o">=</span> <span class="s">"*"</span> <span class="c1"># Added by alr</span></code></pre>
<p>C’est bien mais pas complétement, on voit une première erreur.<br>
Les exécutables produits sont faux. On ne génère plus cet exécutable, <em>cbsg_examples</em>, mais <em>produce_corporate_bullshit</em>… Simple à modifier.</p>
<p>L’autre chose, c’est que l’on voit bien la dépendance vers la <em>crate cbsg</em> avec n’importe quelle version (le "*"). Pour plus d’informations, il faut aller voir <a href="https://alire.ada.dev/docs/#release-information">la doc d’Alire sur les informations du TOML</a> (ça fait du <em>semver</em> pour la sélection des versions de <em>crate</em>).</p>
<h3 id="toc-on-est-en-dev-on-na-rien-publié">On est en dev, on n’a rien publié</h3>
<p>Dans notre cas, comme la <em>crate cbsg</em> n’a pas été publiée, on fait un <a href="https://alire.ada.dev/docs/#work-in-progress-dependency-overrides"><em>override</em></a>, on va donc ajouter un petit morceau à notre TOML pour préciser où trouver notre dépendance.</p>
<pre><code class="toml"><span class="p">[[</span><span class="n">pins</span><span class="p">]]</span>
<span class="n">cbsg</span> <span class="o">=</span> <span class="p">{</span> <span class="n">path</span> <span class="o">=</span> <span class="s">"../cbsg"</span> <span class="p">}</span> <span class="c1"># Overridden by local version</span></code></pre>
<p>Et voilà, on a ajouté une épingle sur la version à utiliser, il s’agira de celle se trouvant dans le répertoire <em>cbsg</em>.</p>
<p>Le fichier complet devient donc : </p>
<pre><code class="toml"><span class="n">name</span> <span class="o">=</span> <span class="s">"cbsg_examples"</span>
<span class="n">description</span> <span class="o">=</span> <span class="s">"Corporate bullshit generator examples"</span>
<span class="n">version</span> <span class="o">=</span> <span class="s">"0.0.1"</span>
<span class="n">authors</span> <span class="o">=</span> <span class="p">[</span><span class="s">"Gautier de Montmollin"</span><span class="p">]</span>
<span class="n">maintainers</span> <span class="o">=</span> <span class="p">[</span><span class="s">"Frédéric Praca <xxxxxxxxx>"</span><span class="p">]</span>
<span class="n">maintainers-logins</span> <span class="o">=</span> <span class="p">[</span><span class="s">"FredPraca"</span><span class="p">]</span>
<span class="n">executables</span> <span class="o">=</span> <span class="p">[</span><span class="s">"produce_corporate_bullshit"</span><span class="p">]</span>
<span class="p">[[</span><span class="n">depends-on</span><span class="p">]]</span> <span class="c1"># Added by alr</span>
<span class="n">cbsg</span> <span class="o">=</span> <span class="s">"*"</span> <span class="c1"># Added by alr</span>
<span class="p">[[</span><span class="n">pins</span><span class="p">]]</span>
<span class="n">cbsg</span> <span class="o">=</span> <span class="p">{</span> <span class="n">path</span> <span class="o">=</span> <span class="s">"../cbsg"</span> <span class="p">}</span> <span class="c1"># Overridden by the latest sources</span></code></pre>
<h3 id="toc-on-teste">On teste</h3>
<pre><code>fred@tatooine:~/Dev/Ada/cbsg_examples$ alr run
</code></pre>
<p>Si cela n’a pas déjà été contsruit, on a l’étape de construction et le lancement de l’exécutable.</p>
<pre><code>Compile
[Ada] produce_corporate_bullshit.adb
[Ada] delirium.adb
[Ada] corporate_bullshit.adb
Build Libraries
[gprlib] Cbsg.lexch
[archive] libCbsg.a
[index] libCbsg.a
Bind
[gprbind] produce_corporate_bullshit.bexch
[Ada] produce_corporate_bullshit.ali
Link
[link] produce_corporate_bullshit.adb
New corporate bullshit is in bullshit.html. Enjoy. Use switch -h for help about options.
</code></pre>
<p>Le programme écrit par défaut un fichier HTML que vous pouvez ouvrir avec votre navigateur préféré pour obtenir une belle série de bullshits :)</p>
<p>Si on ne veut pas de fichier HTML:</p>
<pre><code>fred@tatooine:~/Dev/Ada/cbsg_examples$ bin/produce_corporate_bullshit --one
Roles and responsibilities consistently engage goals-based and cloud-based timelines.
</code></pre>
<h2 id="toc-conclusion">Conclusion</h2>
<p>Le but de cet article était de présenter <em>Alire</em> de façon un peu plus ludique que la documentation officielle en fournissant un premier exemple. Cela a permis de montrer toutefois le <em>pinning</em> de version que l’on peut considérer comme une utilisation avancée.</p>
<p>Alire est un outil en cours de développement et les <em>crates</em> ne sont pas encore nombreuses, on n’en compte que 243 à ce jour, mais tout cela est d’ores et déjà utilisable.<br>
<em>Alire</em> contient des <em>crates</em> diverses et variées qui peuvent couvrir le développement standard tout comme le développement embarqué <a href="https://fr.wikipedia.org/wiki/Bare_metal"><em>bare metal</em></a> ou le développement <a href="https://en.wikipedia.org/wiki/SPARK_(programming_language)"><em>Spark</em></a>.</p>
<p>D’ailleurs, si cela n’a été qu’effleurer, <em>Alire</em> permet la gestion des <em>toolchains</em> au sein des <em>crates</em>, permettant ainsi de préciser une dépendance à un compilateur particulier. Ainsi, certaines <em>crates</em> tirent une dépendance vers le compilateur croisé <a href="https://fr.wikipedia.org/wiki/Architecture_ARM">ARM</a></p>
<p>Si Alire, tout comme <em>pip</em>, <em>cargo</em> ou <em>npm</em> rentre en collision avec le gestionnaire de paquets de votre distribution, cela reste toutefois un bon moyen de développer rapidement du code Ada.</p>
<p>Cherry on the cake, si vous avez <a href="https://en.wikipedia.org/wiki/GNAT_Programming_Studio"><em>GnatStudio</em></a> d’installé, la commande <em>alr edit</em> ouvrira le projet dans celui-ci :)</p>
<p>Amusez-vous bien !</p>
</div><div><a href="https://linuxfr.org/news/alire-le-package-manager-d-ada.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/127856/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/alire-le-package-manager-d-ada#comments">ouvrir dans le navigateur</a>
</p>
BlackknightXavier TeyssierPierre JarillonBenoît SibaudYsabeau 🧶 🧦https://linuxfr.org/nodes/127856/comments.atomtag:linuxfr.org,2005:Bookmark/45992022-04-26T08:02:07+02:002022-04-26T08:02:07+02:00Comment installer Firefox en paquet Debian sur Ubuntu 22.04 (pas en Snap)<a href="https://www.omgubuntu.co.uk/2022/04/how-to-install-firefox-deb-apt-ubuntu-22-04">https://www.omgubuntu.co.uk/2022/04/how-to-install-firefox-deb-apt-ubuntu-22-04</a> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/127573/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/lawless/liens/comment-installer-firefox-en-paquet-debian-sur-ubuntu-22-04-pas-en-snap#comments">ouvrir dans le navigateur</a>
</p>
Lawlesshttps://linuxfr.org/nodes/127573/comments.atomtag:linuxfr.org,2005:Post/409322020-03-18T22:57:43+01:002020-03-19T09:26:51+01:00Problème mise à jour Ubuntu<p>Bonsoir,</p>
<p>Depuis quelques jours, j'ai un problème lors de la mise à jour d'Ubuntu.<br>
En effet, lorsque je tape la commande : sudo apt dist-upgrade</p>
<p>L'erreur suivante apparaît : </p>
<pre><code class="sh">Préparation du dépaquetage de .../signond_8.60+r698+dbusapi1+pkg3~daily~ubuntu5.0.1_amd64.deb ...
Dépaquetage de signond <span class="o">(</span><span class="m">8</span>.60+r698+dbusapi1+pkg3~daily~ubuntu5.0.1<span class="o">)</span> sur <span class="o">(</span><span class="m">8</span>.59+17.10.20170606-0ubuntu1<span class="o">)</span> ...
dpkg: erreur de traitement de l<span class="s1">'archive /var/cache/apt/archives/signond_8.60+r698+dbusapi1+pkg3~daily~ubuntu5.0.1_amd64.deb (--unpack) :</span>
<span class="s1"> tentative de remplacement de « /usr/share/dbus-1/services/com.google.code.AccountsSSO.SingleSignOn.service », qui appartient aussi au paquet gsignond 1.1.0~r509+pkg4~daily~ubuntu5.0.1</span>
<span class="s1">Des erreurs ont été rencontrées pendant l'</span>exécution :
/var/cache/apt/archives/signond_8.60+r698+dbusapi1+pkg3~daily~ubuntu5.0.1_amd64.deb
E: Sub-process /usr/bin/dpkg returned an error code <span class="o">(</span><span class="m">1</span><span class="o">)</span></code></pre>
<p>Après quelques recherches sur Internet, j'ai aussi essayé :<br>
sudo apt-get install -f<br>
et aussi<br>
sudo apt-get -f install</p>
<p>Mais cela ne change rien. <br>
Auriez-vous une solution à me proposer s'il-vous-plaît ?</p>
<div><a href="https://linuxfr.org/forums/linux-debutant/posts/probleme-mise-a-jour-ubuntu.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/119691/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/linux-debutant/posts/probleme-mise-a-jour-ubuntu#comments">ouvrir dans le navigateur</a>
</p>
Hayato175https://linuxfr.org/nodes/119691/comments.atomtag:linuxfr.org,2005:Post/408312020-02-09T11:19:32+01:002020-02-09T11:19:32+01:00Installer un package de stable dans une debian testing<p>Bonjour,<br>
je voudrais installer Ardour sur ma debian testing. Mais il n'est pas dans la liste des paquets. Par contre il est présent dans le dépôt "sable". Est-ce que c'est une bonne idée de l'installer en rajoutant le dépôt "stable" dans mon sources.list ?<br>
merci de vos conseils</p>
<div><a href="https://linuxfr.org/forums/linux-debian-ubuntu/posts/installer-un-package-de-stable-dans-une-debian-testing.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/119372/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/linux-debian-ubuntu/posts/installer-un-package-de-stable-dans-une-debian-testing#comments">ouvrir dans le navigateur</a>
</p>
max22https://linuxfr.org/nodes/119372/comments.atomtag:linuxfr.org,2005:Bookmark/6862019-06-05T06:00:23+02:002019-06-05T06:00:23+02:00Argh-P-M! – Dissecting the RPM file format<a href="https://xyrillian.de/thoughts/posts/argh-pm.html">https://xyrillian.de/thoughts/posts/argh-pm.html</a> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/117404/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/guillawme/liens/argh-p-m-dissecting-the-rpm-file-format#comments">ouvrir dans le navigateur</a>
</p>
Guillawmehttps://linuxfr.org/nodes/117404/comments.atomtag:linuxfr.org,2005:Diary/377392018-02-13T21:03:35+01:002018-02-13T21:03:35+01:00Petit guide à l'usage des développeurs de LL qui souhaitent se tirer dans le piedLicence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li><ul>
<li><a href="#de-lutilit%C3%A9-des-mainteneurs">De l'utilité des mainteneurs</a></li>
<li><a href="#la-situation">La situation</a></li>
<li><a href="#que-retenir">Que retenir</a></li>
</ul></li>
</ul><h3 id="de-lutilité-des-mainteneurs">De l'utilité des mainteneurs</h3>
<p>Contrairement au monde Windowsien, il est très peu commun pour un utilisateur de Linux ou BSD (voire même MacOS, avec HomeBrew) d'installer directement un logiciel depuis le site web de son développeur. Le plus clair du temps, on passe plutôt par un <em>dépôt</em> (de binaires ou de sources) : cela permet aux utilisateurs de ne pas avoir à se soucier de la configuration particulière de leur distribution préférée et de centraliser les installations et mises à jour.</p>
<p>Cela met toutefois en exergue le rôle crucial mais trop souvent méconnu de <em>mainteneur</em>. C'est grâce à eux que vous pouvez trouver facilement vos logiciels et que les patchs nécessaires à leur fonctionnement sont appliqués. C'est aussi parfois eux qui maintiennent le logiciel alors que les développeurs originaux (upstream) sont passés à une version plus récente. C'est finalement souvent eux qui remontent les bogues et s'assurent de rapatrier leur correction dans leur distribution. Bref, en tant que développeur, les mainteneurs vous permettent de diffuser gratuitement votre logiciel à des millions de personnes. D'où l'idée de ne pas se les mettre à dos. </p>
<h3 id="la-situation">La situation</h3>
<p>Observons donc <a href="https://github.com/jasperla/openbsd-wip/issues/86">ce qu'il ne faut pas faire</a>. Pour résumer l'histoire :</p>
<ul>
<li><p>Un bénévole travaillant sur les <em>ports</em> d'OpenBSD décide d'intégrer <em>Pale Moon</em>. C'est un fork de Firefox, et donc un logiciel libre. Il poste un premier message sur les forums de Pale Moon indiquant 1) qu'il faudrait qu'il applique certains patchs pour contourner certains problèmes spécifiques et 2) qu'ayant lu le contrat de licence et ayant constaté que la redistribution sous le même nom ne pouvait se faire qu'avec l'accord des développeurs, il voudrait savoir si un tel arrangement pourrait être fait.</p></li>
<li><p>Moins de 2 heures plus tard, une <em>issue</em> <a href="https://github.com/jasperla/openbsd-wip/issues/86">est soulevée sur le dépôt GitHub des mainteneurs</a> :</p></li>
</ul><blockquote>
<p>You will revise your mozconfig […] You must comply with the directive or you must disable official branding […] Additionally, you will please explain and justify the patches you are applying</p>
</blockquote>
<p>Le ton est toujours difficile à traduire d'une langue à l'autre, mais l'utilisation de <em>will</em> et <em>must</em> est l'équivalent de l'impératif en français.</p>
<ul>
<li><p>Le mainteneur (le même qui avait originellement posté sur les forums de Pale Moon) rétorque qu'il souhaite discuter avec le détenteur des droits et non se faire poser des ultimatums ainsi.</p></li>
<li><p>Le dit détenteur intervient alors :</p></li>
</ul><blockquote>
<p>Your insistence to only speak to me in person about such matters is ridiculous, considering the license is up on the website, worded clearly for everyone to see, and you're clearly not adhering to it. But, here I am, as requested. Now, follow the license terms, please. I will not be as educational next time.</p>
</blockquote>
<p>La dernière phrase étant pour le moins indicatrice de l'état général de la conversation.</p>
<ul>
<li>La discussion s'enflamme (des 2 côtés) et, quelques heures plus tard, le mainteneur publie sa décision :</li>
</ul><blockquote>
<p>This issue is now officially resolved. There will be no Pale Moon browser, official or not. The port has been removed. Farewell, petulant children.</p>
</blockquote>
<ul>
<li>Toute cette agitation a amené d'autres BSD à se demander s'ils n'étaient pas aussi en violation de la dite licence et, dans le cas de FreeBSD au moins, <a href="https://lists.freebsd.org/pipermail/freebsd-ports/2018-February/112455.html">il s'avère que oui</a>.</li>
</ul><h3 id="que-retenir">Que retenir</h3>
<p>Il y a plusieurs choses à considérer dans cette histoire. Premièrement, le point de vue technique : ce n'est pas par hasard que les distributions veulent compiler les logiciels libres en utilisant leurs propres librairies et directives de compilation. Le tout est très bien résumé <a href="https://lists.freebsd.org/pipermail/freebsd-ports/2018-February/112459.html">dans ce message</a>, mais, pour faire simple, cela permet à la fois de mieux assurer la sécurité de l'utilisateur, de retirer une charge de maintenance des développeurs upstream et de faciliter la mise à jour (contrairement à, par exemple, Windows, où chaque logiciel embarque justement ses propres versions de chaque librairie). Ce genre de restriction est tout simplement impossible à appliquer dans le cas général et dénote une certaine incompréhension de la manière dont les distributions (Linux ou BSD) fonctionnent.</p>
<p>Deuxièmement, le point de vue légal/philosophique : ce genre de restrictions commence sérieusement à s'éloigner des objectifs du logiciel libre. Protéger une marque est une chose, utiliser ce copyright pour mettre en place des mesures restreignant la liberté des utilisateurs en est une autre. Certes, on pourra me rétorquer que Mozilla a fait la même chose avec Firefox (d'où le fork IceWeasel), mais voilà : Mozilla n'est jamais allé aussi loin. Si la diffusion sous le nom de Firefox d'un binaire recompilé à partir de sources modifiées était effectivement prohibée, les mainteneurs ont toujours eu toute la latitude pour modifier les paramètres de compilation.</p>
<p>Troisièmement, le point de vue humain : lorsqu'il y a des gens qui travaillent bénévolement pour diffuser votre travail et font des efforts honnêtes pour vous contacter et prendre votre avis en compte, la moindre des choses est de ne pas leur cracher au visage moins de 3 heures après les présentations. Ce n'est pas de dire que tout développeur dans une situation similaire devrait se garder de toute critique, mais qu'il y a une façon de la formuler. Si vous arrivez sur vos grands chevaux, ne vous étonnez pas d'être reçus avec mépris par quelqu'un qui, au final, ne vous doit rien.</p>
<p>Tout bien réfléchi, la perte de réputation pour Pale Moon (qui est un navigateur de niche) est probablement plus préjudiciable que tout problème ayant pu survenir à cause d'une librairie mal configurée par un mainteneur…</p><div><a href="https://linuxfr.org/users/kalenx/journaux/petit-guide-a-l-usage-des-developpeurs-de-ll-qui-souhaitent-se-tirer-dans-le-pied.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/113736/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/kalenx/journaux/petit-guide-a-l-usage-des-developpeurs-de-ll-qui-souhaitent-se-tirer-dans-le-pied#comments">ouvrir dans le navigateur</a>
</p>
Kalenxhttps://linuxfr.org/nodes/113736/comments.atomtag:linuxfr.org,2005:Post/365292016-02-21T17:53:17+01:002016-02-23T20:26:48+01:00[resolu] Paquets à conseiller pour création d'illustrations et printables<p>Bonjour.</p>
<p>Je souhaite créer des illustrations et printables et les mettre en format pdf et .je</p>
<p>Je suis sous debian. Avez vous des logiciels à me recommander?</p>
<p>Merci d'avance.</p><div><a href="https://linuxfr.org/forums/linux-debian-ubuntu/posts/resolu-paquets-a-conseiller-pour-creation-d-illustrations-et-printables.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/108267/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/linux-debian-ubuntu/posts/resolu-paquets-a-conseiller-pour-creation-d-illustrations-et-printables#comments">ouvrir dans le navigateur</a>
</p>
Fatmahttps://linuxfr.org/nodes/108267/comments.atomtag:linuxfr.org,2005:Post/351822015-04-01T09:31:40+02:002015-04-01T09:31:40+02:00Installer un package en sid<p>Bonjour,<br>
je cherche à installer un package sur la debian que j'utilise. Mais étant sur une wheezy-backports, lorsque j'utilise apt-get il me dit que pleins de paquets sont indisponible :<br><a href="https://packages.debian.org/wheezy-backports/handbrake">https://packages.debian.org/wheezy-backports/handbrake</a><br>
En effet.<br>
Donc je me dit que je pourrai installer ce fameux package en prenant plutôt ceux de sid…<br>
Je rajoute l'url deb pour sid, je l'ajoute temporairement dans l'apt/source.list, j'update et je tente:<br>
274Mo à mettre à jour. Il y a le logiciel que je veux dans le lot, mais une autre centaine inutile. Or je ne veux pas mettre à jour les autres logiciels.<br><a href="https://packages.debian.org/sid/handbrake">https://packages.debian.org/sid/handbrake</a><br>
Est-ce que c'est possible de le faire sans rendre instable le système? Ou dans mon cas les dépendances sont telles qu'il faut mettre forcément à jour les autres services ayant appui sur les mêmes solutions devant se mettre à jour ou y a t-il une solution pour être sûr de n'installer que les packages nécessaire pour le logiciel que je souhaite récupérer?</p>
<p>Merci d'avance.</p>
<p>--depuis j'ai retiré la source sid de la /apt/source.list en attendant.</p><div><a href="https://linuxfr.org/forums/linux-debian-ubuntu/posts/installer-un-package-en-sid.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/105288/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/linux-debian-ubuntu/posts/installer-un-package-en-sid#comments">ouvrir dans le navigateur</a>
</p>
dafphttps://linuxfr.org/nodes/105288/comments.atomtag:linuxfr.org,2005:Post/350632015-03-02T14:55:00+01:002015-03-02T14:55:00+01:00Un peu d'aide pour un débutant<p>Bonjour,</p>
<p>Je me lance vite fait dans Linux avec quelques distributions du genre Mint, Debian et Ubuntu et Fedora</p>
<p>J'ai quelques bases et aujourd’hui"hui, je dois tester un logiciel réseau pour les onduleurs et les cartes SNMP afin que ce logiciel envois bien un ordre de shutdown à la machine ( virtuelle ou physique)</p>
<p>A l'heure actuel j'ai ce paquet </p>
<p>(liens vers mon drop box)<br><a href="https://www.dropbox.com/l/PIkCkCKQ3bj7VsfO9tVx7q">https://www.dropbox.com/l/PIkCkCKQ3bj7VsfO9tVx7q</a></p>
<p>Il n'y a pas de version plus recente, je viens de vérifier sur le site du constructeur des cartes SNMP</p>
<p>J'arrive à installer ce paquet, via Alien pour debian ubuntu et mint, mais une fois l'installation faite, le logiciel ( dont je connais le fonctionnement sur Windows) ne se lance pas.</p>
<p>Et du coup, comme c'est très particulier, et que je ne sais pas où chercher, et quoi chercher surtout, et bien je suis légèrement perdu</p>
<p>Un peu d'aide serai vraiment le bien venu.</p>
<p>Merci d'avance à qui me lira</p><div><a href="https://linuxfr.org/forums/linux-debian-ubuntu/posts/un-peu-d-aide-pour-un-debutant.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/104965/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/linux-debian-ubuntu/posts/un-peu-d-aide-pour-un-debutant#comments">ouvrir dans le navigateur</a>
</p>
Jlbhttps://linuxfr.org/nodes/104965/comments.atomtag:linuxfr.org,2005:Post/350612015-03-01T16:10:13+01:002015-03-01T16:10:13+01:00Paquet de experimental a unstable<p>Bonjour à tous,<br>
J'aimerai faire une chose un peu particulière avec le gestionnaire de paquets de debian, mais je ne sais pas si c'est possible:<br>
je viens de mettre à jour inkscape à partir du dépôt experimental (j'ai une priorité = 500 dans le apt/preferences pour l'experimental). <br>
J'aimerai pouvoir le marquer à nouveau jessie ou unstable sans qu'il ne rétrograde, de manière à ce qu'il "attende" que la version jessie ou unstable rattrape la version courante (ou je sais, on est en freeze etc., mais bon). Est-ce que cela est possible avec les outils apt, dpkg ou autre?</p>
<p>Merci d'avance</p><div><a href="https://linuxfr.org/forums/linux-debian-ubuntu/posts/paquet-de-experimental-a-unstable.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/104956/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/linux-debian-ubuntu/posts/paquet-de-experimental-a-unstable#comments">ouvrir dans le navigateur</a>
</p>
icefingerhttps://linuxfr.org/nodes/104956/comments.atom