Perl : lire un fichier de configuration
Nous l'avons vu il y a quelques mois, il est parfois nécessaire qu'un script Perl reçoive des ordres spécifiques via des arguments sur la ligne de commande. Dans la majorité des cas, cela est suffisant pour de petits scripts, mais lorsqu'il s'agit d'applications plus complètes ou nécessitant des arguments plus grands (ou plus difficiles à saisir), il est nécessaire de placer les arguments dans un fichier : un fichier de configuration.
Bien que Perl possède des particularités qui lui permettent de très facilement lire un fichier texte pour y récupérer les informations importantes, il existe une meilleure solution. Certains modules permettent de simplifier grandement la gestion de fichiers de configuration. L'un d'entre eux, nommé AppConfig, est sans doute le plus simple, le plus complet et le plus largement utilisé. Ce module est l'
uvre d'Andy Wardley et est disponible sur cpan.
Utilisation simple
AppConfig permet de lire (parser) le fichier de configuration et fournit des méthodes pour récupérer des variables et leur valeur dans le fichier de configuration. Ces variables peuvent être booléennes, scalaires ou encore des listes ou des hashes. La composition des variables est fixée par une configuration préalable. Passons directement à la pratique avec un fichier de configuration qui contiendra ceci :
# mon fichier de config à moi
test
debug
niveau = 4
repertoire = /tmp
repertoire = /var
repertoire = /home
Nous avons ici plusieurs types d'éléments :
- un commentaire précédé d'un # qui ne sera pas considéré comme une ligne active du fichier de configuration ;
- des variables booléennes (test et debug). Leur simple présence suffit à activer une fonctionnalité dans le script.
- une variable initialisée avec un scalaire ;
- un paramètre répété dont nous expliquerons la gestion dans le script qui va suivre.
Voici notre premier script. Comme à l'accoutumée, nous faisons preuve de prudence dans le développement et nous assurons que n'importe quel code douteux sera signalé :
#!/usr/bin/perl -w
use strict;
Nous pouvons ensuite utiliser notre nouveau module :
use AppConfig qw(:expand :argcount);
La liste passée en paramètre spécifie que nous souhaitons faire usage des constantes prédéfinies par le module. Nous allons en voir immédiatement la raison en structurant les informations que nous allons récupérer dans le fichier de configuration :
my $config = AppConfig->new(
'test', 'debug',
'niveau' => ARGCOUNT => 1 ,
'repertoire' => ARGCOUNT => ARGCOUNT_LIST);
La méthode new d'AppConfig permet de créer un nouvel objet de configuration. Celui-ci sera défini par les lignes qui sont passées en argument. Tout d'abord, les mots clefs test et debug sont des variables booléennes. Inutile de spécifier quoi que se soit dans ce cas.
Nous passons au mot clef niveau qui consistera en une valeur scalaire. Ici, nous spécifions que nous attendons un argument (4 dans le présent fichier de configuration). Enfin, nous nous intéressons aux diverses occurrences du mot clef repertoire. Au final, nous souhaitons obtenir une liste et le spécifions donc par la constante ARGCOUNT_LIST.
Nous venons de créer un objet $config que nous pouvons maintenant initialiser avec les valeurs présentes dans le fichier :
$config->file('denis.conf');
Enfin, nous pouvons en faire usage. Commençons par les plus simples :
print "test : ", $config->test(), "n";
print "debug : ", $config->debug(), "n";
print "niveau : ", $config->niveau(), "n";
Nous n'avons qu'à utiliser les méthodes portant les mêmes noms que les mots clefs du fichier de configuration. Il en va tout autrement pour notre liste. En effet, $config->repertoire() nous renvoie une référence vers la liste. Nous devons donc stocker cette référence et en faire usage ensuite :
my $rep = $config->repertoire();
foreach my $i (@$rep)
print "$in";
Vous pouvez le constater, AppConfig est si simple à mettre en
uvre qu'il sera même utilisé pour un petit script. C'est fini, nous pouvons exécuter notre script et constater que tout fonctionne à merveille :
$ ./simple.pl
test : 1
debug : 1
niveau : 4
/tmp
/var
/home
Arguments
AppConfig pourra également être utilisé pour lire des arguments passés en paramètre sur la ligne de commande. Il suffit pour cela d'utiliser la méthode args immédiatement après $config->file(). Ainsi, les arguments proposés en ligne viennent écraser les valeurs placées dans le fichier de configuration. En modifiant notre code et en ajoutant $config->args();, nous pouvons essayer la commande suivante :
$ ./simple -repertoire /toto -nodebug -niveau 6
test : 1
debug : 0
niveau : 6
/tmp
/var
/home
/toto
Le fichier de configuration n'a pas changé. Vous noterez cependant que les lignes debug et niveau ont changé et qu'une nouvelle entrée dans la liste repertoire est présente. Les variables booléennes et scalaires du fichier ont été écrasées par les nouvelles valeurs spécifiées sur la ligne de commande. La méthode args prend en compte n'importe quel paramètre préfixé par - ou -- ; de plus, si la chaîne "no" est ajoutée au mot clef et qu'il s'agit d'un argument booléen, il devient une négation (ceci est également valable pour le fichier de configuration). Dans le cas des listes ou des hashes, l'argument est simplement ajouté.
Utilisation avancée
Même si dans bien des cas la configuration et le code que nous venons de présenter est suffisant, il peut arriver que vous ayez besoin de structurer davantage votre configuration. AppConfig vous sera d'autant plus utile qu'il utilise, lui aussi, une manière très structurée pour gérer la configuration.
Pour étudier les fonctionnalités avancées, nous allons créer un second fichier de configuration contenant :
# second fichier de configuration
debug off
entree premier = "et un !"
entree second = "et deux !"
entree troisieme = "et trois !"
[section1]
niveau = 7
[section2]
niveau = 12
Nous avons affaire ici à trois nouveaux types de mots clefs/variables. La première ligne est un booléen, mais utilisé à l'aide d'un argument définissant sa valeur vrai/faux. Nous résoudrons ce problème très facilement grâce à l'utilisation d'une constante définie par AppConfig :
my $config = AppConfig->new(
'debug' => ARGCOUNT => ARGCOUNT_NONE,
Plutôt que ne rien spécifier pour ARGCOUNT comme précédemment, nous déterminons de manière claire que ce mot clef ne prend pas d'argument avec ARGCOUNT_NONE. Ceci nous apporte une amélioration par rapport au code précédent ; un argument peut être utilisé mais il ne fera que déterminer la valeur booléenne de debug. Ainsi, avec la ligne debug off dans le fichier de configuration, debug sera faux. ARGCOUNT_NONE apporte une plus grande souplesse. Voici quelques exemples :
Toutes ces syntaxes valent vrai :
debug
debug = 1
debug on
debug nimportekoi
Toutes ces syntaxes valent faux :
nodebug
debug = 0
debug off
Le problème suivant porte sur le groupe de trois lignes utilisant la syntaxe :
mot-clef référence = valeur
Cette même syntaxe est utilisée dans le système entier pour, par exemple, définir des alias de commande :
alias l = 'ls -la'
Il n'y a pas besoin d'être un grand expert en Perl pour comprendre que ce type de donnée, idéal dans ce cas, est un hash. Et justement, AppConfig utilise une constante spécifique dans ce but :
'entree' => ARGCOUNT => ARGCOUNT_HASH ,
Nous pourrons ensuite utiliser la référence retournée par $config->entree() de la même manière qu'avec le format de la liste dans le code précédent.
Enfin, nous arrivons au problème de section. Ici, AppConfig gère cela de manière simple en préfixant le nom de la variable avec le nom de la section. Nous aurons donc :
'section1_niveau' => ARGCOUNT => ARGCOUNT_ONE ,
et
'section2_niveau' => ARGCOUNT => ARGCOUNT_ONE );
Nous venons de déterminer la structure dont nous aurons besoin ; voici le code correspondant au nouveau fichier de configuration dans son ensemble :
#!/usr/bin/perl -w
use strict;
use AppConfig qw(:expand :argcount);
my $config = AppConfig->new(
'debug' => ARGCOUNT => ARGCOUNT_NONE ,
'entree' => ARGCOUNT => ARGCOUNT_HASH ,
'section1_niveau' => ARGCOUNT => ARGCOUNT_ONE ,
'section2_niveau' => ARGCOUNT => ARGCOUNT_ONE );
$config->file('denis1.conf');
print "debug : ", $config->debug(), "nn";
my $entree = $config->entree();
foreach my $k (keys %$entree)
print "clef : "$k"nvaleur : "$entree->$k"nn";
print "section1_niveau : ", $config->section1_niveau(), "n";
print "section2_niveau : ", $config->section2_niveau(), "n";
Celui-ci nous permet de lire le fichier et d'afficher ceci :
$ ./simple2.pl
debug : 0
clef : "troisieme"
valeur : "et trois !"
clef : "second"
valeur : "et deux !"
clef : "premier"
valeur : "et un !"
section1_niveau : 7
section2_niveau : 12
Encore plus loin
Ne comptez pas utiliser les deux scripts tels quels dans votre application Perl ! Nous ne nous sommes basés que sur des exemples de fichier de configuration ne comportant ni erreur, ni mauvaise syntaxe. Un véritable code devra vérifier les éléments avant de les utiliser.
Avant tout, nous devons nous assurer de la présence du fichier et des permissions le concernant. Pour cela, nous avons besoin d'obtenir des informations sur le fichier de configuration et faisons usage de File::stat :
use File::stat;
$info=stat("denis2.conf")
or die "Impossible d'avoir les informations !n";
if ($info->uid != $<)
print ("Mauvais propriétaire !n");
exit;
else
if (($info->mode & 07777) != oct(600))
print ("Permissions incorrectes !n");
exit;
Nous considérons ici que vous aurez besoin que l'utilisateur lançant le script soit aussi propriétaire du fichier, mais également que personne d'autre ne puisse lire les informations qui s'y trouvent. Bien sûr, cela dépend du type d'application que vous allez écrire, mais dans bien des cas, mieux vaut limiter au maximum les permissions. Vous pourrez toujours assouplir le programme par la suite.
La seconde vérification devra porter sur la présence des divers mots clefs dans le fichier de configuration. Il est donc important de vérifier la présence des variables avant de vous en servir car AppConfig ne met à notre disposition aucun mécanisme de ce type.
En revanche, il peut être utile de devoir appeler un code spécifique dans certaines situations, comme une erreur ou simplement une notification. Ceci peut être fait via une entrée spécifique dans la structure de configuration :
my $config = AppConfig->new(
'niveau' =>
ARGCOUNT => ARGCOUNT_ONE,
VALIDATE => &verif);
Grâce à une entrée VALIDATE, nous pouvons spécifier un code qui retournera une réponse, comme par exemple ceci :
sub verif
my $variable = shift;
my $value = shift;
if ($value < 10)
$reponse = 1;
else
$reponse = 0;
return $reponse;
Ici, le test est très simple, nous vérifions si la valeur est inférieure à 10. Si c'est le cas, notre code renvoie 1 (oui), sinon il renvoie 0 (non). Ainsi, avec une ligne niveau = 12, nous obtiendrons une erreur :
niveau: invalid value: 12 at denis1.conf line 12
Mais si, plus loin dans le code, nous désirons faire :
print "niveau : ", $config->niveau(), "n";
nous obtiendrons également une erreur. C'est donc au programmeur de prendre ses dispositions pour arrêter le script si une erreur est détectée dans le fichier de configuration.
A l'instar de VALIDATE, ACTION permet de faire référence à un code, mais celui-ci sera appelé dès que la valeur de la variable changera. Voici un exemple :
my $config = AppConfig->new(
'niveau' =>
ARGCOUNT => ARGCOUNT_ONE,
ACTION => &monaction );
sub monaction
my $state = shift;
my $variable = shift;
my $value = shift;
print "$variable --> $valuen";
$config->niveau(45);
Notre ligne niveau = 12 reste inchangée dans le fichier de configuration et pourtant, en exécutant le code, nous obtenons :
niveau --> 12
niveau --> 45
Notre code est donc bel et bien exécuté dès que la valeur de niveau change et ce, quel que soit l'endroit dans le script.
Conclusion
AppConfig est sans conteste le module à choisir si vous désirez utiliser rapidement un fichier de configuration dans l'un de vos scripts Perl. N'oublions pas cependant que la grande mode est actuellement l'unification des fichiers de configuration dans un format universel : XML.
Nous verrons une autre fois comment utiliser un fichier XML dans nos scripts et, pourquoi pas, lire des fichiers de configuration d'autres applications utilisant ce format.
Copyright (c) Linux Magazine France
Permission vous est donnée de distribuer des copies exactes de cette page tant que cette note de permission et le copyright apparaissent clairement.