Évolution de la difficulté du minage de Bitcoin

Le Bitcoin est une monnaie cryptographique dont la validation des transactions est faite par une preuve de travail. La preuve de travail consiste à trouver un condensat (hash) commençant par un certain nombre de zéros.

Nombre de zéro au début du hash d’une transaction

Un hash de transaction (Transaction Hash ID) ressemble, par exemple, à 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f. Dans ce cas, 10 zéros débutent le hash.

Plus le nombre de zéro exigé est élevé, plus il est difficile de trouver une solution. Ce nombre évolue au fil du temps : si une solution est trouvée rapidement, le nombre de zéro augmente pour les transactions suivantes (et inversement).

Évolution jusqu’à aujourd’hui

Croissance du nombre de zéros requis au fil du temps

En bleu, les statistiques de l’ensemble des transactions contenues dans la chaîne. En orange, la moyenne des transactions de chaque journée. Les points noirs représentent les moyennes mensuelles.

La difficulté est croissante, avec parfois des plateaux. Cela montre indirectement l’augmentation de la puissance de calcul au fil du temps (le nombre de machines minant augmente, les processeurs sont plus performants, etc.).

Cela mesure encore plus imparfaitement la pollution générée par l’utilisation :

  • d’énergies renouvelables : à une période où le prix du Bitcoin était faible, une stratégie de minimisation des coûts a poussé certains à se limiter à la consommation d’excédents d’énergie hydroélectrique ou éolienne.
  • d’énergie fossile : le prix actuel pousse à la relance de centrales à gaz ou à charbon.

Production du graphique

Il est possible de voir les informations d’une transaction sur des services web mais autant extraire les informations à partir de la chaîne Bitcoin avec le client grâce à un script shell suivant :

#! /bin/sh
MAX_BLOCK=$(./bin/bitcoin-cli getblockcount)

for i in $(seq 1 $MAX_BLOCK); do {
HASH=$(./bin/bitcoin-cli getblockhash $i)
./bin/bitcoin-cli getblock $HASH | jq '[.time, .hash] | @csv' | sed 's/[\"]//g' >> stats_brutes.csv
}
done

Le script nécessite que la chaîne complète soit disponible sur la machine. La chaîne consomme presque 400 Go d’espace disque. La version du client et serveur était la 0.21.1.
Les commandes du binaire bitcoin-cli sont documentées sur https://developer.bitcoin.org/reference/rpc/index.html.
La production des statistiques au format .csv est très loooongue car le client bitcoin met du temps à répondre.

Une fois les données extraites au format .csv, un script python utilise la bibliothèque matplotlib pour produire le graphique :

import csv
import datetime
import time

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np

def draw_graph(csv_path):
    SIZE = 0.5
    stats_completes, stats_quotidiennes, stats_mensuelles = stats(csv_path)
    fig, ax = plt.subplots()
    ax.plot_date(stats_completes["x"], stats_completes["y"], markersize=SIZE, label="Tous", color="blue")
    ax.plot_date(stats_quotidiennes["x"], stats_quotidiennes["y"], markersize=SIZE*2, label="Quotidien", color="orangered")
    ax.plot_date(stats_mensuelles["x"], stats_mensuelles["y"], markersize=SIZE*2, label="Mensuel", color="black")
    fmt_year = mdates.YearLocator()
    ax.xaxis.set_major_locator(fmt_year)
    fmt_month = mdates.MonthLocator()
    ax.xaxis.set_minor_locator(fmt_month)
    ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
    ax.fmt_xdata = mdates.DateFormatter('%Y-%m-%d %H:%M:%S')
    fig.autofmt_xdate()

    ax.grid(True)
    plt.xlabel("Temps")    
    plt.ylabel("Nombre de zéros")
    plt.legend(loc="upper left", markerscale=4)
    plt.savefig("./graph_bitcoin_zeros.png", dpi=150)

def stats(path):
    x_toutes, y_toutes = [], []
    with open(path, newline='') as csv_file:
        stats_reader = csv.reader(csv_file)
        for ligne in stats_reader:
            date = _from_timestamp(ligne[0])
            nb_zeros = _nb_zeros(ligne[1])
            x_toutes.append(date)
            y_toutes.append(nb_zeros)
    stats_quotidiennes = _stats_quotidiennes(x_toutes, y_toutes)
    stats_mensuelles = _stats_mensuelles(x_toutes, y_toutes)
    return {"x": x_toutes, "y": y_toutes}, stats_quotidiennes, stats_mensuelles

def _stats_quotidiennes(x_toutes, y_toutes):
    dates_possibles = set([(date.year, date.month, date.day) for date in x_toutes])
    stats_quot = {date: [] for date in dates_possibles}
    for index, x in enumerate(x_toutes):
        stats_quot[x.year, x.month, x.day].append(y_toutes[index])
    x, y = [], []
    for mois in sorted(dates_possibles):
        x.append(datetime.datetime(mois[0], mois[1], mois[2]))
        y.append(_moyenne(stats_quot[mois]))
    return {"x": x, "y": y}

def _stats_mensuelles(x_toutes, y_toutes):
    dates_possibles = set([(date.year, date.month) for date in x_toutes])
    stats_mois = {date: [] for date in dates_possibles}
    for index, x in enumerate(x_toutes):
        stats_mois[x.year, x.month].append(y_toutes[index])
    x, y = [], []
    for date in sorted(dates_possibles):
        x.append(datetime.datetime(date[0], date[1], 15))
        y.append(_moyenne(stats_mois[date]))
    return {"x": x, "y": y}

def _moyenne(valeurs):
    return sum(valeurs) / len(valeurs)

def _from_timestamp(data):
    return datetime.datetime.fromtimestamp(int(data))

def _nb_zeros(data):
    count = 0
    for lettre in data:
        if lettre == "0":
            count += 1
        else:
            return count

        
if __name__ == "__main__":
    draw_graph("stats_brutes.csv")

Le script python utilise un type de graphique idéal pour le besoin, déjà inclus dans Matplotlib. 🙂

Catégories :Autre

Démontage WD Elements Play

WD Elements Play était un boîtier multimédia vendu par Western Digital à partir des années 2010. Apparemment c’était un système assez limité dès sa sortie. Il semble que Western Digital ait simplement utilisé une conception faite chez Amlogic, en y incluant sa propre production de disque dur.

Composants

Le démontage du boîtier est aisé : il faut retourner le boîtier et déclipser le fond à l’aide d’un tournevis plat. Le disque dur se retire directement en le reculant pour le déconnecter du connecteur SATA, puis un deuxième cran pour pouvoir le sortir du boîtier. Une vidéo youtube faite par quelqu’un d’autre montre ce processus.

La carte qui fait l’intermédiaire entre les Entrées/Sorties et le disque dur est basée sur une puce Amlogic AML8626-H aux spécifications mystérieuses.

Le disque dur est au format 3,5 pouces et d’une taille de 1To. Sur le côté du disque, on peut voir les vis, chacune avec une pièce en caoutchouc pour retenir le disque dans le boîtier.

Quel format pour le disque ?

Étant donné qu’il s’agit d’un disque standard, il suffit de le brancher sur une machine quelconque pour le détecter (ici sur /dev/sdb) :

# fdisk -l
[...]
Disk /dev/sdb: 931,51 GiB, 1000204886016 bytes, 1953525168 sectors
Disk model: WDC WD10EADS-11M
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: dos
Disk identifier: 0x9a6027cc

Device Boot Start End Sectors Size Id Type
/dev/sdb1 2048 1953521663 1953519616 931,5G 27 Hidden NTFS WinRE

Parted est d’accord avec fdisk :

# parted -l
[...]
Model: ATA WDC WD10EADS-11M (scsi)
Disk /dev/sdb: 1000GB
Sector size (logical/physical): 512B/4096B
Partition Table: msdos
Disk Flags: 

Number  Start   End     Size    Type     File system  Flags
 1      1049kB  1000GB  1000GB  primary  ntfs         msftres

L’équivalent graphique avec gparted

Il y a donc une partition unique, au format Microsoft NTFS. L’intérêt est probablement d’avoir un format reconnu nativement par des machines Windows car il est possible de brancher le boîtier en USB pour le relier à un ordinateur.

Regarder le contenu du disque est trivial :

# mkdir /tmp/ntfs
# mount -t ntfs /dev/sdb1 /tmp/ntfs

ls /tmp/ntfs montre des fichiers comme la corbeille (RECYCLER), un répertoire autorun et un fichier autorun.inf (probablement utilisé lors du branchement en USB du boîtier sur un système Windows), un répertoire System Volume Information avec un point de restauration (peut-être pour une réinitialisation usine?) et un répertoire fourni par WD contenant un peu de documentation au format pdf. Bien évidemment, on y retrouve aussi les fichiers déposés par l’utilisateur.

Les versions des logiciels qui n’auront pas été maltraités malgré une partition NTFS:

  • fdisk et mount(util-linux 2.36.1)
  • parted (GNU parted) 3.4
  • GParted 1.2.0
Catégories :Autre Étiquettes :

Coloration syntaxique de votre code avec Pygments

J’ai publié un article dans Linux Pratique n°115 (septembre 2019) intitulé « Coloration syntaxique de votre code avec Pygments ». Il est disponible publiquement sur le site des éditions Diamond, sous licence Creative Commons BY-NC-ND.

Les éditions Diamond proposent 3 modes de cession des droits pour les articles dont une qui permet la republication sous cette licence, 6 mois après la publication papier (cession de droits type B).

Dans ce cas où l’article disparaîtrait du site Diamond, je le reproduis ci-dessous :

Mieux visualiser du code source grâce à sa coloration est une évidence. Découvrez Pygments, un outil de coloration facilement utilisable et extensible.

Pygments [1] est un outil écrit en Python permettant de colorer du code pour plus d’une centaine de langages de programmation ou de description (HTML, XML, TeX), de moteurs de templates (ERB, JSP, Jinja2, etc.) et divers scripts et fichiers de configuration (Vim, fichiers .ini, Apache, Nginx). Deux façons de l’utiliser coexistent :

  • comme une bibliothèque ;
  • grâce à un exécutable (pygmentize), il est utilisable directement dans un terminal.

Pygments est disponible pour python 2 et 3.

Nous verrons quelques usages de cet outil puis la façon d’y ajouter un langage et un thème.

1. Usages

1.1 Dans un terminal

L’usage le plus simple se résume à appeler pygmentize uniquement avec le nom du fichier à colorer en paramètre :
pygmentize fichiers.pl

Cette commande affiche le contenu d’un fichier nommé fichiers.pl sur la sortie standard avec la coloration syntaxique par défaut. Cependant, pygmentize dispose de paramètres pour personnaliser la sortie selon ses préférences:
pygmentize -f terminal256 -O style=friendly -g fichiers.pl

Le paramètre -f définit le type de sortie souhaitée. De nombreux formats sont disponibles, allant du HTML au Latex en passant par la génération d’une image contenant le code à colorer. terminal256 est un mode pour la sortie standard d’une console.
Le paramètre -O définit la couleur et la graisse des caractères. 29 possibilités sont disponibles dans la version 2.2.0 (nommées algol, autumn, emacs, friendly, vim, etc.).
Le paramètre -g indique que le lexeur à utiliser est déterminé par l’extension de fichier.

Application du style friendly au contenu du fichier fichiers.pl

Cependant, il est bien plus pratique d’ajouter un alias pour pouvoir l’appeler rapidement :

alias hcat='pygmentize -f terminal256 -O style=friendly -g'

Selon le shell utilisé, il faut l’insérer dans un fichier différent : ~/.bash_profile or ~/.bashrc pour bash, ~/.zshrc pour zsh et ~/.config/fish/config.fish pour fish.

1.2 Avec Latex

Minted est un paquet Latex permettant de réaliser une coloration syntaxique de code source. Il utilise pygments pour faire la coloration.

Il est utilisable en insérant le code source au sein du fichier latex :

\begin{minted}
[
% configuration du style
% (taille des caractères, numérotation des lignes, etc.)
]
{perl}
% ici le code source
\end{minted}

Ou en gardant le code source dans un fichier externe :
\inputminted{perl}{fichiers.pl}

Dans les deux exemples précédents, le motif {perl} définit le lexeur utilisé par pygments.

1.3 Présentation avec rst2pdf

rst2pdf produit un PDF de présentation à partir d'un fichier texte au format ReStructured Text. Il réutilise aussi pygments pour faire la coloration syntaxique. Les présentations sont par défaut très épurées.

rst2pdf.py presentation.txt -o presentation.pdf

rst2pdf est disponible dans le paquet éponyme dans Debian et ses distributions dérivées.

1.4 Pour le web

Pygments est utilisé dans des outils web écrits en Python, comme par exemple le moteur de wiki Moinmoin ou le générateur de site statique Pelican. Hugo, un autre générateur de site statique, utilisait pygments pour la coloration syntaxique mais l'a remplacé par chroma, un outil en Go. Chroma réutilise les définitions les plus courantes de pygments pour son propre usage. Django, le framework web le plus connu du monde Python dispose aussi d'un module pour s'interfacer avec pygments.

Pour les autre langages, la tendance est plutôt à l’utilisation de solutions natives au langage (côté serveur) ou l’utilisation d’une bibliothèque javascript (côté client) comme highlight.js qui dispose de nombreux de langages/fichiers de configuration et d’une intégration aisée.

2. Ajouter un lexeur

Ajouter un lexeur permet de prendre en compte un nouveau langage ou format de fichier (texte). Le lexeur doit être défini dans une classe Python qui intégrera les expressions rationnelles analysant le texte.

À titre d'illustration, nous allons utiliser une partie du format Smart Game Format (sgf) [2] qui sert à l'enregistrement de certains jeux à deux joueurs ; le plus connu étant le jeu de Go. Le lexeur complet a été intégré dans la dernière version de pygments (2.4.0, publiée en mai 2019).

Note : Qu’est-ce qu’un lexeur ?

Un lexeur est un programme analysant un texte en le découpant en une suite d’entités lexicales (par exemple, un entier, une chaîne de caractères, une définition d’un type, etc.). La phase d’analyse lexicale faite par un lexeur est la première étape d’une compilation d’un programme.

Le développement d'un nouveau lexeur est facilité par l'utilisation de paramètres supplémentaires à pygmentize. En supposant que la classe définissant le lexeur soit nommée SmartGameFormatLexer et contenue dans le fichier sgf.py et que le fichier à analyser soit nommé partie.sgf, la commande sera :
pygmentize -l sgf.py:SmartGameFormatLexer -x partie.sgf

Un extrait de partie.sgf pourrait être :
(;FF[4]GM[1]SZ[19]KM[5.5]
PB[Alice]PW[Bob]
;B[pe];W[cp];B[pp];W[dd])

La structure des données est toujours basée sur le motif mot-clef[données].
Il est nécessaire de séparer :
– les mots-clefs (FF, GM, SZ, KM, PB, PW, B et W) ;
– les données qui peuvent être des nombres entiers (comme 4) ou décimaux (5.5) ou encore du texte. Ce dernier est utilisé ici pour les noms des participants (Alice et Bob) ou les coordonnées du plateau (pe représentant la colonne p et la ligne e) ;
– les séparateurs (parenthèses, crochets, deux-points et point-vigule) :

from pygments.lexer import RegexLexer, bygroups
from pygments.token import Name, Number, \
    Punctuation, String


class SmartGameFormatLexer(RegexLexer):
    name = 'SmartGameFormat';
    aliases = ['sgf']
    filenames = ['*.sgf']

    tokens = {
        'root': [
            (r'[\s():;]';, Punctuation),
            # tokens:
            (r'(B|FF|GM|KM|P[BW]|SZ|W)',
             Name),
            # number:
            (r'(\[)([0-9.]+)(\])',
             bygroups(Punctuation, Number, Punctuation)),
            (r'(\[)([\w\s#()+,\-.:?]+)(\])',
             bygroups(Punctuation, String, Punctuation)),
       ],
    }

L'attribut filenames (ligne 9) est utilisé par le paramètre -g de pygmentize pour déterminer le lexeur à utiliser pour colorer un fichier (cf. le deuxième exemple de cet article). Seuls les fichiers finissant par .sgf seront analysés par SmartGameFormatLexer. Il est possible d'accepter plusieurs extensions de fichier : par exemple, pour le lexeur du C++, 12 extensions sont acceptées (.cpp, .c++, .cxx, .hpp, …).

Les expressions rationnelles permettent d'éclater le contenu du fichier et de définir le type (chaîne de caractères, opérateur, commentaire, entier, etc.).

L'analyse du dictionnaire des symboles commence par la clef root du dictionnnaire tokens en cherchant la première correspondance possible dans la liste avec l’expression rationnelle. Une fois la correspondance trouvée, l’analyse des motifs permet de connaître le type de la chaîne. Par exemple, la chaîne FF va correspondre à l’expression rationnelle r'(B|FF|GM|KM|P[BW]|SZ|W)' et donc sera analysée comme étant de type Name. Il est possible de faire reconnaître plusieurs symboles dans la même expression rationnelle : c’est le cas de la chaîne [4] qui est reconnue par l’expression rationnelle (\[)([0-9.]+)(\]). Les trois motifs entre parenthèses seront affectés aux paramètres passé à la fonction bygroups() (donc [ correspond au type Punctuation, 4 à Integer et ] à Punctuation).

Pour des besoins plus complexes, il est possible d’ajouter des clefs à tokens pour passer à une autre liste d’expressions rationnelles. Dans ce cas, il est possible d’aller une clef à l’autre puis de revenir à la précédente. Il est aussi possible d'appeler d'autres lexeurs dans un lexeur particulier ou d’appeler une fonction spécifique pour gérer des cas particuliers.

3. Ajouter un style

Pour ajouter un nouveau thème de couleur, il faut créer un fichier qui sera placé dans le répertoire contenant les styles de pygments. Pour éviter de modifier la version du système, il suffit de créer un environnement local. Python permet cela en créant un virtualenv:


$ python3 -m venv venv
$ ./venv/bin/pip install pygments
$ touch venv/lib/python3.7/site-packages/pygments/styles/glmf.py

Le nom du fichier et la classe définie à l'intérieur sont dépendants du nom que l'on souhaite donner au thème : pour que le style soit nommé glmf, le fichier doit s’appeler glmf.py et la classe qu’il contient doit être nommée GlmfStyle.

Pour tester le résultat en affichant le script Perl précédent :
$ ./venv/bin/pygmentize -f terminal256 -O style=glmf -g fichiers.pl

Remplissons le fichier glmf.py :

from pygments.style import Style
from pygments.token import Comment, Keyword, Name, Number, \
    Operator, Punctuation, String
     

class GlmfStyle(Style):
    default_style = ""
    styles = {
        Comment:                'underline #808',
        Keyword:                'bold #00f',
        Name:                   '#f00',
        Number:                 'bold ansicyan',
        Operator:               'bg:ansired ansibrightyellow',
        Punctuation:            '#0f0',
        String:                 'bg:#fff #222',
    }

À chaque type de symboles est associé un style à afficher avec une couleur, soit avec une valeur hexadécimale (ici #808 s’affiche en violet), soit avec un nom ansi (comme ansicyan). Il est possible de modifier l’affichage en soulignant (underline), en mettant en gras (bold), en définissant une couleur de fond (bg:#fff pour un fond blanc). Il est aussi possible d’utiliser des italiques(italic) mais cela n’aura pas d’incidence sur une sortie dans un terminal (mais sera visible sur une sortie html par exemple).

Application du style glmf toujours sur le même fichier. C’est tout de même plus… personnel, non ?

Conclusion

Pygments est une référence classique pour de la coloration syntaxique dans l’écosystème Python et est utilisé au-delà. La difficulté d’ajout d’un lexeur est fonction de la complexité du langage à traiter. L’ajout de style est plus simple mais sa plus-value est probablement plus faible.

Références

[1] Site officiel de pygments : http://pygments.org/
[2] Définition du format SGF : https://www.red-bean.com/sgf/

Catégories :Python

Un an de commit sur cpython

Dans une base de code source, certaines parties sont plus modifiées que d’autres. cpython ne déroge pas à la règle. En analysant les fichiers modifiés durant l’année 2020, on peut voir l’activité intégrée à la branche principale (nommée master).

L’activité d’un fichier est estimée en comptant le nombre de fois où il a été modifié. Dans cet article, l’estimation de l’activité d’un répertoire est la somme de l’activité des répertoires et des fichiers qu’il contient. Par exemple, avec un répertoire R contenant 3 fichiers F1, F2 et F3, un premier commit modifiant F1 et F2, un second modifiant uniquement F2, alors l’activité de F1 vaut 1, F2 vaut 2 et F3 vaut 0. L’activité de R vaut (1 + 2 + 0).

Activité globale

La quantité totale de modifications enregistrées est de 9956.

L’activité dans les répertoires à la racine du dépôt est principalement dans :

  • Lib : code python de la bibliothèque standard
  • Doc : documentation au format reStructuredText. Elle permet la génération de plusieurs documentations visibles sur python.org (dont celle de la bibliothèque standard)
  • Misc : quelques fichiers divers et un répertoire résumant les nouveautés de chaque version
  • Modules : code python et C

Ces quatre répertoires représentent 2/3 de l’activité.

Il existe aussi quelques fichiers à la racine mais leur activité est négligeable.

Dans le répertoire Lib

60% de l’activité dans Lib se situent dans Lib/test et sont donc liés à la modification ou l’ajout de tests unitaires. Étant donné que la bibliothèque standard est couverte par des tests unitaires, il est assez logique que cela représente une part importante de l’activité. Ce répertoire ne contient pas l’intégralité des tests : certains sont placés ailleurs dans l’arborescence. Par exemple Lib/idlelib/idle_test, Lib/distutils/tests, etc.
Loin derrière, et pourtant deuxième en terme d’activité dans Lib, le répertoire idlelib contient du code de l’éditeur IDLE (4%).
Les onze premiers modules actifs (en excluant les tests) représentent 19% de l’activité :

L’activité autour de IDLE me semble étonnante car j’ai l’impression que cet éditeur est peu utilisé et donc je l’imaginais peu actif. De même pour tkinter mais son activité est probablement liée à IDLE qui l’utilise comme interface graphique.

Dans le répertoire Doc

La moitié de l’activité dans ce répertoire est liée à la bibliothèque standard (dans Doc/library). C’est assez logique puisque Lib est très modifié donc la documentation correspondante doit être mise à jour (pour signaler une changement de comportement, un nouveau paramètre, etc.).

Ensuite, avec 20% de l’activité, le répertoire Doc/whatsnew contient les notes de version. L’année a vu la sortie de python 3.9 et le début du développement de la version 3.10 donc on retrouve principalement des modifications pour ces deux fichiers. Je suppose que les autres versions sont dues à des rétroportages ou des modifications cosmétiques.

        whatsnew (267)
            3.9.rst (150)
            3.10.rst (95)
            3.8.rst (10)
            3.7.rst (5)
            3.2.rst (3)
            3.3.rst (1)
            3.5.rst (1)
            3.6.rst (1)
            index.rst (1)

Ce répertoire contient de nombreux autres fichiers de version, commençant avec 2.0.rst, qui n’ont eu aucune activité.

Dans le répertoire Misc

L’activité dans le répertoire Misc est due à l’ajout des nouvelles qui sont placées dans Misc/NEWS.d (94%). Chaque nouveauté ou changement de comportement ajouté à une nouvelle version publiée donne lieu à un nouveau fichier. Contrairement à des fichiers .py qui sont régulièrement modifiés, ces fichiers sont ajoutés en grand nombre mais ne sont plus jamais modifiés. Cet ajout est la dernière étape à effectuer pour proposer une modification sur le code de cpython.
Le fichier ACKS contient 5% des modifications : ce fichier regroupe le nom de toutes les personnes qui ont au moins contribué une fois. Il est donc logique que ce répertoire soit souvent modifié.

Dans le répertoire Modules

Le répertoire Modules contient une partie du code C de l’interpréteur. Contrairement aux répertoires précédents, l’activité est répartie beaucoup plus largement.
Il faut les 14 premiers répertoires et fichiers pour représenter 50% de l’activité de Modules.

Méthode de calcul et limites

Le code source ayant permis de produire l’arborescence d’activité est disponible à https://github.com/sblondon/commitstats. J’espère qu’il n’y a pas d’anomalie (ou sans impact réel) sur les calculs de stats.

L’arborescence est affichée sur la sortie standard :

. (9956)
    Lib (2765)
        test (1695)
            test_asyncio (74)
                test_events.py (11)
                test_tasks.py (10)
[...]
    README.rst (12)
    .travis.yml (10)
    aclocal.m4 (6)
    .gitattributes (2)
    .gitignore (2)
    LICENSE (2)
    m4 (2)
        ax_c_float_words_bigendian.m4 (1)
        ax_check_openssl.m4 (1)

Les fichiers de statistiques générés sont téléchargeables. Les scripts de génération des graphiques y sont aussi (et ont encore moins d’intérêt).

Seule la branche master est prise en compte donc les développements en cours et ceux en attente d’intégration sont ignorés.

Les modifications considèrent l’ensemble de l’année 2020 donc une partie des développements de la version 3.9 et le début de 3.10 puisque la version 3.9 est sortie en octobre 2020.

Plutôt que de compter le nombre de fois qu’un fichier a été modifié, il serait peut-être préférable de compter le nombre total de lignes modifiées.

La bibliothèque tree_output https://pypi.org/project/tree_output/ permettrait une sortie plus élégante.

Catégories :Python

Effet boomerang pour les contributions à du logiciel libre

Lorsqu’on corrige une anomalie ou qu’on a ajoute une fonctionnalité à un logiciel ou une bibliothèque, on peut la garder pour soi ou la partager. La deuxième solution demande un peu plus d’efforts à court terme mais est préférable à long terme.

Le délai de retour d’un correctif ou d’une amélioration dépend de l’endroit où il est proposé : plus il est poussé loin et plus il va mettre de temps à revenir mais le nombre de personnes/machines bénéficiant du correctif sera plus grand.

Les différentes possibilités

Effet boomerang d'une contribution

Gardé pour soi

Cette méthode est absente du schéma puisqu’elle consiste à ne pas envoyer la modification à l’extérieur. C’est le plus rapide à mettre en œuvre, d’autant plus que la qualité du correctif n’est validée qu’en interne (juste soi-même ou par l’équipe intégrant la modification). Diverses façons d’arriver à ses fins sont possibles comme surcharger la signature de la méthode qui pose problème, attraper l’erreur non traitée correctement, intégrer la bibliothèque dans le code et la modifier directement (vendoring), etc.

Par contre, personne d’autre ne bénéficie du correctif et personne d’extérieur ne fera une revue de code.

Publication solitaire

La vitesse de mise au point est équivalente à la méthode précédente. Le déploiement prend un peu de temps. Elle permet de rendre la modification disponible pour les autres utilisateurs s’ils la trouvent. Ce phénomène est visible avec l’incitation au fork proposée par les forges comme Github, Gitlab, Bitbucket, etc, sans pousser la modification vers le développeur amont (via une pull request). Cette technique est utilisée lorsque des développeurs :

  1. forkent un dépôt,
  2. créent un commit modifiant le nouveau dépôt,
  3. font dépendre leur application de ce commit (npm install git+https://alice@forge...).

Cependant, ce comportement n’est pas limité aux forges publiques : il existait déjà avant en publiant le correctif dans un article de blog, une liste de diffusion (liste non exhaustive).

Envoyé vers la distribution

La correction est envoyée dans la distribution Linux utilisée ; c’est souvent fait en incluant la modification dans un fichier, attaché à un rapport de bogue sur la distribution.

Une fois que la modification sera intégrée et qu’un nouveau paquet sera publié, l’ensemble des utilisateurs, y compris l’auteur, en bénéficieront. Cela évite de maintenir la modification de son côté lorsque de nouvelles versions du paquet seront publiées. La durée d’intégration est plus longue selon la réactivité du mainteneur du paquet et le mode de publication (version espacée ou rolling release). Bien évidemment, le bénéfice de la modification sera perdu en cas de changement de distribution.

Cette solution est nécessaire pour corriger/améliorer un élément spécifique d’un paquet de la distribution. Cela peut arriver dans deux cas :

  • soit parce que c’est un paquet spécifique à la distribution (le paquet apt pour debian par exemple)
  • soit parce qu’une modification du logiciel spécifique à la distribution a une influence sur la modification soumise

Envoyé vers le développeur amont

Plutôt que d’envoyer le correctif vers la distribution utilisée, il est alors envoyé directement vers le développeur du logiciel. Si le développement est hébergé sur une forge publique, cela suppose le faire un fork (comme dans le cas d’une publication solitaire), puis de faire une pull request (terme Github), merge request (terme Gitlab). Sinon, il faut regarder quelle est la forme attendue : en postant sur une liste de diffusion, ou directement vers le mainteneur, etc. Il sera nécessaire de répondre aux remarques et demandes de corrections pour que la modification soit intégrée dans le logiciel amont.

Comme dans le cas d’une intégration dans la distribution, une fois intégrée, la modification sera disponible pour tous :

  • soit en réutilisant le logiciel directement via le paquet issus du langage (par exemple gem pour ruby, wheel pour python, crate pour Rust, etc.)
  • soit parce que la version du logiciel sera elle aussi intégrée dans la distribution et donc obtenue dans un paquet de la distribution

Ce type de contributions sont les plus longues à revenir au contributeur mais elles permettent le déploiement le plus large (et donc la plus grande disponibilité pour soi et pour les autres).

Autres considérations

S’il n’est pas possible d’attendre le retour de la modification, la solution optimale est de faire un correctif local et un envoi vers la distribution ou vers le développeur amont (pour qu’une solution long terme soit aussi disponible automatiquement).

Pour bénéficier de l’envoi amont, il faut que le temps de retour soit inférieur au temps de changement de techno/bibliothèque. Dans un écosystème où les outils et bibliothèques sont abandonnés très rapidement, l’effort d’intégration peut être perçu comme vain puisque la personne ayant fait le développement aura peu le temps d’en profiter. D’un point de vue général, avec une majorité de personnes faisant ce calcul, cela ne fait qu’empirer le problème, avec des multitudes de fork s’ignorant mutuellement, chacun avec une fonctionnalité ou une correction différente. Javascript me semble être dans cette situation.

À propos du schéma

Le schéma a été réalisé avec Dia, installable par le paquet du même nom pour Debian et dérivées.
Fichier source .dia

Catégories :Debian