Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

  1. #1
    Responsable Perl et Outils

    [FAQ] Comment lister les modules installés sur une machine ?
    Bonjour,

    Beaucoup de personnes ont dû déjà se poser la question de comment lister les modules installés sur son PC en vu d'un changement de matériel. Voici la solution que je propose de rajouter dans la FAQ.

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #!/usr/bin/perl 
    use strict;
    use warnings;
    use ExtUtils::Installed;
     
    my $inst = ExtUtils::Installed->new();
    foreach ( sort $inst->modules() ) {
    	print "Module $_ [" . $inst->version($_) . "]\n";
    }


    ou

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    perl -MExtUtils::Installed -e "my $inst = ExtUtils::Installed->new(); print qq{Module $_ [} . $inst->version($_) . qq{]\n} foreach sort $inst->modules();"


    Qu'en pensez-vous ?

  2. #2
    Membre actif
    Bonjour djibril,

    Y-a-il déjà une entrée dans la FAQ sur la question (je n'en ai pas vu) ?

    Il y a de nombreuses façons de faire, en fonction aussi de ce que l'on cherche, outre celle que tu proposes : http://www.perlmonks.org/?node_id=868141

    sinon ton oneliner sous Linux avec bash donne une erreur en raison de l'expansion des variables que fait le shell.

    tu devrais donc plutôt utiliser la single quote pour éviter cela :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    perl -MExtUtils::Installed -e '$inst = ExtUtils::Installed->new(); print qq{Module $_ [} . $inst->version($_) . qq{]\n} foreach sort $inst->modules();'


    et une utilisation de ExtUtils::Installed pour afficher la liste des core modules serait aussi éventuellement utile.

    Eks

  3. #3
    Responsable Perl et Outils

    Ton code ne fonctionne pas sous Windows à cause des simples quotes . Il faut une solution multiplate-forme.
    Le but de ce poste est de trouver un bout de code fonctionnel pour le rajouter dans la FAQ.

  4. #4
    Membre actif
    oui :-)

    Ce n'est pas le code qui est en cause, mais le shell, qui est différent.

    Je pense qu'il faut simplement avertir que avec un shell windows, ce sont des guillemets qu'il faut utiliser et avec un shell faisant une expansion des variables comme bash sous Linux (et d'autres), ce sont des apostrophes, et prendre le parti de proposer une forme ou l'autre.

    Ce problème n'est pas particulier à cette question de la FAQ, mais concernerait toute question pour laquelle un oneliner est proposé.

    S'il y en a d'autres dans la FAQ, ce problème est-il traité, si oui, comment ?

    La majorité des oneliners disponible sur l'Internet utilisent des apostrophes, les utilisateurs de Perl étant le plus souvent sous un unix-like...

    Cela dit, la personne qui utilise son propre shell devrait savoir comment l'utiliser.. cela n'est pas vraiment lié à Perl.


    Eks

  5. #5
    Responsable Perl et Outils

    C'est sûr qu'il est préférable de proposer deux onliners pour Windows unix-like. C'est le cas dans la FAQ, mais bon, quand on peut avoir une seule version pour les deux, c'est toujours mieux.

    Pour revenir à la question, j'essaye de proposer une solution simple et rapide pour faire un état des lieux rapide des modules installés sur son PC. Ensuite, à chacun d'aller plus loin si besoin.
    Dans tous les cas, je pense qu'il est important d'avoir les informations suivantes :
    • nom du module ;
    • sa version ;
    • peut-être savoir s'il était dans le core ou non.


    N.B. La plus part du temps, lorsque l'on fait cela, c'est que l'on a envie de changer de PC afin de tout réinstaller.
    Je suis donc preneur de toute solution efficace. Le but est de le partager via la FAQ à tous les lecteurs.

  6. #6
    Membre actif
    ExtUtils::Installed fait partie de core depuis Perl v5.005, alors je pense que c'est un bon choix de l'utiliser si le but est de répondre "dans le cas d'une migration", et le nom du module et la version me semblent suffisants pour ce besoin.

    La sortie va aussi indiquer la version de Perl utilisée, ce qui permet de savoir quelle version de Perl devrait être installée. Cette information suffit à permettre la réinstallation à l'identique.

    Savoir quels sont les modules présents dans core me semble correspondre à un autre besoin :

    - je migre sur une machine qui a une version supérieure de Perl, et je veux savoir si tel ou tel module fait partie de core dans cette version
    - j'envisage d'utiliser tel module dans mon application, et je veux vérifier qu'il est compatible avec mes prérequis de fonctionnement, et savoir la version de Perl à partir de laquelle un module donné est d'office disponible avec Perl

    Dans ce cas corelist me semble préférable (qui dépend de Module::CoreList qui est dans core depuis 2008 avec Perl v5.8.9).

    Liste de tous les modules core de Perl pour la version 5.14.2 :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    corelist -v 5.14.2


    Liste des versions de Perl contenant un module donné dans core :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    corelist -a ExtUtils::Installed


    http://perldoc.perl.org/corelist.html

    corelist ou un script avec Module::CoreList pourrait aussi être utilisé sur la machine cible ayant une version différente de Perl, avec en entrée la liste produite par ton oneliner pour vérifier si les modules concernés n'ont pas, par hasard été intégrés dans la nouvelle version de Perl.


    Eks

  7. #7
    Rédacteur/Modérateur

    J'allais justement mentionner corelist et Module::Corelist, mais, bon c'est fait.

    Pour trouver l'ensemble des modules disponibles, j'avais aussi proposé il y a quelques mois (peut-être même un an) ce script uniligne pour la section sur les unilignes::

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
     
    perl -M5.10.1 -e 'sub search {for $d (glob qq|$_[0]/*|) { -d $d ? search ($d) : say $d if $d =~ /\.pm/;}} search ($_) for (@INC)'


    Mais l'utilisation du module ExtUtils::Installed, que je ne connaissais pas, est sans doute meilleure et apporte plus d'informations (en particulier la version du module).

  8. #8
    Membre actif
    J'ai fait un petit script (check_installed_mod.pl ci-dessous) qui est destiné à la machine cible et qui combine l'usage de Module::CoreList et de ExtUtils::Installed et de version.pm (qui permet de normaliser les numéros de version Perl et les comparer - ce module est également dans core depuis 2008 avec Perl v5.8.9) pour traiter la sortie de ton oneliner.

    Donc, on peut faire, sur la machine d'origine :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    perl -MExtUtils::Installed -e '$inst = ExtUtils::Installed->new(); print qq{Module $_ [} . $inst->version($_) . qq{]\n} foreach sort $inst->modules();' > installed_mod.txt


    puis, on peut utiliser le fichier installed_mod.txt sur la machine cible avec un script comme celui-ci

    check_installed_mod.pl :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    #!/usr/bin/perl 
    use strict;
    use warnings;
    use Module::CoreList;
    use ExtUtils::Installed;
    use version;
     
    my $inst = ExtUtils::Installed->new();
    my @mods = $inst->modules();
     
    print "Cette machine dispose de Perl $^V\n";
     
    while (<>)
    {
        if (/^Module ([^ ]+) \[([^\]]+)/) {
            my ($mod, $ver) = ($1, $2);
            if (exists $Module::CoreList::version{$]}{$mod}) {
                print "[OK]\t$mod [$Module::CoreList::version{$]}{$mod}] est un core module\n";
                print "Warning : sur l'autre machine la version est $ver\n" if ( version->parse($Module::CoreList::version{$]}{$mod}) < version->parse($ver) );
            } elsif (/$mod/ ~~ @mods) {                                                                                                                                                                                
                print "[OK]\t$mod [" . $inst->version($mod). "] est déjà installé\n";
                print "Warning : sur l'autre machine la version est $ver\n" if ( version->parse($inst->version($mod)) < version->parse($ver) );
            } else {
                print "[NOK]\t--> $mod [$ver] manquant\n";
            }
        } else {
            print "Erreur de format sur la ligne : $_";
        }
    }


    que l'on passe comme cela :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    cat installed_mod.txt | ./check_installed_mod.pl


    Cela donne une sortie du type :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Cette machine dispose de Perl v5.14.2
    [OK]	Carp [1.20] est un core module
    Warning : sur l'autre machine la version est 1.3301
    [OK]	HTTP::Server::Simple [0.44] est déjà installé
    [NOK]	--> Markdown::Foswiki [0.04] manquant
    [OK]	MIME::Lite [3.030] est déjà installé
    [OK]	Perl [5.14.2] est déjà installé
    [OK]	Sub::Uplevel [0.24] est déjà installé
    [OK]	Test::Warn [0.30] est déjà installé
    [OK]	WWW::Mechanize [1.73] est déjà installé


    Sous Windows, il faut utiliser des guillemets pour ton oneliner et j'imagine qu'il faut utiliser type au lieu de cat et retirer ./ devant le nom du fichier check_installed_mod.pl

    A tester :-)


    Eks

  9. #9
    Responsable Perl et Outils

    Petite amélioration de ton programme. Tu peux l'améliorer :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    #!/usr/bin/perl 
    use strict;
    use warnings;
    use English '-no_match_vars';
    use Module::CoreList;
    use ExtUtils::Installed;
    use version;
    use utf8;
     
    ActiverAccents();
     
    my $inst = ExtUtils::Installed->new();
    my @mods = $inst->modules();
     
    print "Cette machine dispose de Perl $PERL_VERSION\n";
     
    while ( my $ligne = <> ) {
    	chomp $ligne;
     
    	# Module Win32API::Registry [0.30]
    	my ( $mod, $ver ) = $ligne =~ /^Module\s+(\S+)\s+\[(\S+)?\]/i;
    	if ( defined $mod and defined $ver ) {
    		if ( exists $Module::CoreList::version{$]}{$mod} ) {
    			print "[OK]\t$mod [$Module::CoreList::version{$]}{$mod}] est un core module\n";
    			my $ver2 = version->parse( $Module::CoreList::version{$]}{$mod} );
    			if ( $ver2 < version->parse($ver) ) {
    				print "[WARNING]\tsur l'autre machine la version est $ver [ $ver2]\n";
    			}
    		}
    		elsif ( /$mod/ ~~ @mods ) {
    			print "[OK]\t$mod [" . $inst->version($mod) . "] est déjà installé\n";
    			my $ver2 = version->parse( $inst->version($mod) );
    			if ( $ver2 < version->parse($ver) ) {
    				print "[WARNING]\tsur l'autre machine la version est $ver [ $ver2]\n";
    			}
    		}
    		else {
    			print "[NOK]\t--> $mod [$ver] manquant\n";
    		}
    	}
    	elsif ( defined $mod and not defined $ver ) {
    		print "[WARNING]\t$mod : version inconnue sur l'autre machine\n";
    	}
    	else {
    		print "Erreur de format sur la ligne : $ligne\n";
    	}
    }
     
    sub ActiverAccents {
    	my $encodage;
     
    	# Windows
    	if ( lc $OSNAME eq 'mswin32' ) {
    		eval {
    			my ($codepage) = ( `chcp` =~ m/:\s+(\d+)/ );
    			$encodage = "cp$codepage";
    			foreach my $h ( \*STDOUT, \*STDERR, \*STDIN, ) {
    				binmode $h, ":encoding($encodage)";
    			}
    		};
    	}
    	else {
    		$encodage = `locale charmap`;
    		eval {
    			foreach my $h ( \*STDOUT, \*STDERR, \*STDIN, ) {
    				binmode $h, ":encoding($encodage)";
    			}
    		};
    	}
    	return $encodage;
    }


    pour vos contributions.