[couverture de Linux Magazine 101]

Perles de Mongueurs (39)

Article publié dans Linux Magazine 101, janvier 2008.

[+ del.icio.us] [+ Developers Zone] [+ Bookmarks.fr] [Digg this] [+ My Yahoo!]

La perle de ce mois-ci a été rédigée par Philippe "BooK" Bruhat (book@mongueurs.net), de Lyon.pm et Paris.pm.

L'autre moitié de CPAN

Certains modules Perl sont connus pour avoir de très nombreuses dépendances. L'expression consacrée dans la communauté Perl est de dire qu'ils nécessitent « la moitié de CPAN ».

Dès qu'on installe un second framework ou module assez gourmand en dépendances, on se trouve donc obligé d'installer « l'autre moitié de CPAN ». :-)

D'après le fichier 02packages.details.txt.gz du 4 décembre 2007, CPAN contient 50317 modules dans 14260 distributions, par 3511 auteurs. La moitié de tout ça, ça ferait quand même beaucoup...

Tout d'abord, il faut savoir qu'une partie des modules listés dans ce fichier sont les modules du core de Perl, puisque Perl est téléchargeable sur CPAN. Certains sont dans leur propre distribution en plus : c'est ce qu'on appelle les modules dual-lived. Ils ont une double vie, à la fois dans le core de Perl et sur CPAN.

Re-calculons ces chiffres en excluant les modules du core (i.e. les modules livrés avec les sources de Perl). Même s'il existe des mises à jour de ces modules sur CPAN, nous n'en tiendrons pas compte dans nos calculs. Le module Module::CoreList tient à jour la liste de tous les modules fournis directement avec Perl, pour chaque version officielle de Perl.

    use strict;
    use warnings;
    use Module::CoreList;

    my $details_file = shift
        || "$ENV{HOME}/.cpan/sources/modules/02packages.details.txt.gz";
    open my $fh, "gzip -dc $details_file |"
        or die "Impossible d'ouvrir $details_file avec gzip: $!";

    my %count;
    while (<$fh>) {
        next if 1 .. /^$/;    # ignore l'en-tête du fichier
        chomp;
        my ( $module, $version, $distro ) = split ' ';

        next if Module::CoreList->first_release($module);
        $count{distro}{$distro}++;
        $count{module}{$module}++;
    }

    printf "%d modules non-core dans %d distributions sur CPAN\n",
        scalar( keys %{ $count{module} }), scalar keys %{ $count{distro} };

Ce qui nous donne :

    49779 modules non-core dans 14159 distributions sur CPAN

Donc 99% de CPAN n'est pas lié au core de Perl... Ça en fait, des modules originaux !

Quelle moitié de CPAN est installée chez vous ?

Maintenant que vous avez installé quelques un des poids lourds de CPAN (comme Catalyst, Jifty, PPI) et fait quelques blagues sur les multiples moitiés de CPAN que vous avez dû installer, la question finit par vraiment vous tracasser : combien de modules (ou plutôt de distributions) CPAN sont installés chez vous ?

Quand on charge un module Perl à l'aide de use et require, perl parcours les répertoires listés dans le tableau @INC et cherche les fichiers dont le nom est obtenu en remplaçant les :: par des / et en ajoutant le suffixe .pm à la fin.

Nous allons parcourir @INC à la recherche de fichiers .pm pour produire la liste des modules installés. Nous allons ensuite supprimer de cette liste les modules du core (à l'aide de Module::CoreList).

Enfin, à l'aide du contenu de 02packages.details.txt.gz, nous construisons un hash avec trois clés :

À l'aide de ce hash et de la liste des modules non-core installés, nous pouvons faire nos petites statistiques.

    #!/usr/bin/env perl
    use strict;
    use warnings;
    use File::Spec;
    use File::Find;
    use Module::CoreList;    # non core

    # charge le hash des details (cf. routine à la fin)
    my $details_file = shift
        || "$ENV{HOME}/.cpan/sources/modules/02packages.details.txt.gz";

    # construit le hash des relations module-distributions
    open my $fh, "gzip -dc $details_file |"
        or die "Impossible d'ouvrir $details_file avec gzip: $!";
    my $details = {};
    while (<$fh>) {
        next if 1 .. /^$/;    # ignore l'en-tête du fichier
        chomp;
        my ( $module, $version, $distro ) = split ' ';
        next if Module::CoreList->first_release($module);
        $details->{module}{$module}++;
        $details->{distro}{$distro}++;
        $details->{distro_of}{$module} = $distro;
    }
    close $fh;

    # ne garde que les chemins absolus de @INC qui existent
    @INC = grep { -e && File::Spec->file_name_is_absolute($_) } @INC;

    # construit une expression régulière pour supprimer le chemin
    my $INC = qr/^(@{[join '|', map { quotemeta } reverse sort @INC ]})/;

    # récupère les modules non-core installés
    my %modules;
    find(
        sub {

            # ne garde que les fichiers .pm
            return if !-f || !/\.pm$/;

            # supprime le début du chemin
            $File::Find::name =~ /$INC/;
            my $path = File::Spec->abs2rel( $File::Find::name, $1 );
            $path =~ s/\.pm$//;

            # construit le nom du module
            my $module = join '::', File::Spec->splitdir($path);

            # supprime les modules du core
            return if Module::CoreList->first_release($module);

            # ce module nous intéresse
            # (mais ne tenons pas compte des installations multiples)
            $modules{$module}++;
        },
        @INC
    );

    # calcul des statistiques
    printf "%d modules installés\n", scalar keys %modules;

    my @cpan = grep { exists $details->{module}{$_} } keys %modules;
    printf "  dont %d de CPAN (%.2f%% de CPAN)\n", scalar @cpan,
        100 * @cpan / keys %{ $details->{module} };

    my %distro;
    $distro{ $details->{distro_of}{$_} }++ for @cpan;
    printf "  soit %d distributions (%.2f%% de CPAN)\n", scalar keys %distro,
        100 * keys(%distro) / keys %{ $details->{distro} };

Les scores de quelques mongueurs

Sébastien Aperghis-Tramoni installe un nombre non négligeable de modules CPAN afin de les découvrir et de les avoir à portée de main. Ses installations de Perl ressemblent à ceci :

    5783 modules installés
      dont 5362 de CPAN (10.76% de CPAN)
      soit 793 distributions (5.59% de CPAN)

    12578 modules installés
      dont 11629 de CPAN (23.33% de CPAN)
      soit 2251 distributions (15.88% de CPAN)

Ma propre installation de CPAN donne les résultats suivants :

    3204 modules installés
      dont 2147 de CPAN (4.31% de CPAN)
      soit 185 distributions (1.31% de CPAN)

En bref, CPAN est tellement énorme que l'expression « la moitié de CPAN » relève plus du mythe que de la réalité. :-)

À vous !

Envoyez vos perles à perles@mongueurs.net, elles seront peut-être publiées dans un prochain numéro de Linux Magazine.

[IE7, par Dean Edwards] [Validation du HTML] [Validation du CSS]