crackotter has asked for the wisdom of the Perl Monks concerning the following question:
Hello Monks,
I am having a problem finding a efficient way of using a configuration file for my script.
Here is a example:
##Router Identification
router router1 = 192.168.1.2
router router2 = 192.168.1.3
router router3 = 192.168.1.4
router router4 = 192.168.1.5
router router5 = 192.168.1.6
##Set up groups
group1 = router1,router5
group2 = router1, router2, router3
group3 = router2, router3, router4
This would be stored in a configuration (text) file, lets say it is called "router.conf".
I want to load the router section into a hash.
I want to load each to which group to load, and whichever group I load, I want it to be a list or a hash.
Should I be using AppConfig??? If so how??
Thank You,
<TAB>Otter
Re: Configuration File
by legLess (Hermit) on Jul 15, 2003 at 03:47 UTC
|
Use YAML! YAML is a simple, human-readable data-serialization format. It can round-trip any Perl data structure (that anything else can parse, anyway -- nothing's perfect) with no loss, doesn't require evals, and is very easy to work with.
One thing YAML's implementors had in mind at the start was to make a better syntax for config files. YAML's brutally simple in this regard:
# snippet
my $data = "anything you want";
DumpFile( "/path/to/file", $data );
my $newdata = LoadFile( "/path/to/file" );
# now $data == $newdata
The code below is long, but that's mostly data. It dumps the data twice with Data::Dumper, before and after a YAML read/write cycle, just to prove they're the same. Lastly is the data as represented by YAML - very clean and easy to read.
#!/usr/bin/perl
use strict;
use warnings;
use YAML qw/ LoadFile DumpFile Dump /;
use Data::Dumper;
local $Data::Dumper::Indent = 1;
use constant DIV => '-' x 20 . "\n";
my $routers = {
'routers' => {
'router1' => '192.168.1.2',
'router2' => '192.168.1.3',
'router3' => '192.168.1.4',
'router4' => '192.168.1.5',
'router5' => '192.168.1.6',
}
};
my $groups = {
'groups' => {
'group1' => [
'router1',
'router5',
],
'group2' => [
'router1',
'router2',
'router3',
],
'group3' => [
'router2',
'router3',
'router4',
]
}
};
print "Dumping initial data...\n" . DIV;
print Dumper $routers, $groups;
print "Writing YAML file...\n";
DumpFile( "./yaml-test.conf", $routers, $groups );
print "Reading YAML file...\n";
( $routers, $groups ) = LoadFile( "yaml-test.conf" );
print "Dumping YAML'd data...\n" . DIV;
print Dumper $routers, $groups;
print "Dumping YAML'd data with YAML...\n" . DIV;
print Dump $routers, $groups;
And here's the output:
Dumping initial data...
--------------------
$VAR1 = {
'routers' => {
'router5' => '192.168.1.6',
'router1' => '192.168.1.2',
'router3' => '192.168.1.4',
'router4' => '192.168.1.5',
'router2' => '192.168.1.3'
}
};
$VAR2 = {
'groups' => {
'group2' => [
'router1',
'router2',
'router3'
],
'group1' => [
'router1',
'router5'
],
'group3' => [
'router2',
'router3',
'router4'
]
}
};
Writing YAML file...
Reading YAML file...
Dumping YAML'd data...
--------------------
$VAR1 = {
'routers' => {
'router5' => '192.168.1.6',
'router1' => '192.168.1.2',
'router3' => '192.168.1.4',
'router4' => '192.168.1.5',
'router2' => '192.168.1.3'
}
};
$VAR2 = {
'groups' => {
'group2' => [
'router1',
'router2',
'router3'
],
'group1' => [
'router1',
'router5'
],
'group3' => [
'router2',
'router3',
'router4'
]
}
};
Dumping YAML'd data with YAML...
--------------------
--- #YAML:1.0
routers:
router1: 192.168.1.2
router2: 192.168.1.3
router3: 192.168.1.4
router4: 192.168.1.5
router5: 192.168.1.6
--- #YAML:1.0
groups:
group1:
- router1
- router5
group2:
- router1
- router2
- router3
group3:
- router2
- router3
- router4
-- man with no legs, inc. | [reply] [d/l] [select] |
Re: Configuration File
by nite_man (Deacon) on Jul 15, 2003 at 08:44 UTC
|
Try to look at
Config::Tiny. Config file can look like this:
debug = 1
[routers]
router1 = 192.168.1.2
router2 = 192.168.1.3
router3 = 192.168.1.4
router4 = 192.168.1.5
router5 = 192.168.1.6
[groups]
group1 = [router1,router5]
group2 = [router1, router2, router3]
group3 = [router2, router3, router4]
You can get access to the those variables in your script:
use Config::Tiny;
my $conf = Config::Tiny->read('your_config');
my $debug = $conf->{_}->{debug};
my $routers = $conf->{routers}; # Hash ref with routers information
my $groups = $conf->{groups}; # Hash ref with group information
my $router1 = $routers->{router1}; # Router's IP
my $group1 = $groups->{group1}; # Array ref with routers list which be
+long to group 1.
. . .
Hope I helped :)
--------------------------------
SV* sv_bless(SV* sv, HV* stash);
| [reply] [d/l] [select] |
Re: Configuration File
by tcf22 (Priest) on Jul 15, 2003 at 01:17 UTC
|
I think this is what you might be looking for:
#! /usr/bin/perl
use strict;
use Data::Dumper;
my (%routers);
#Load Router list
while(<DATA>){
last if( m/##GROUPS/ );
chomp;
my($name, $ip) = (split(/ /, $_))[1,3];
$routers{$name} = $ip;
}
my $group = 'group2'; #Get group to load here
my (%loaded_routers);
#Load requested group
while(<DATA>){
chomp;
s/ //g; #Clear spaces
my($groupname, $data) = split(/=/, $_);
if($groupname eq $group){
foreach my $n(split(/\,/,$data)){
$loaded_routers{$n} = $routers{$n};
}
last;
}
}
print Dumper \%loaded_routers;
__DATA__
router router1 = 192.168.1.2
router router2 = 192.168.1.3
router router3 = 192.168.1.4
router router4 = 192.168.1.5
router router5 = 192.168.1.6
##GROUPS
group1 = router1,router5
group2 = router1, router2, router3
group3 = router2, router3, router4
The Output:
$VAR1 = {
'router1' => '192.168.1.2',
'router3' => '192.168.1.4',
'router2' => '192.168.1.3'
};
Update:
AppConfig looks like a viable option as well. The above will work on the sample data that you gave, but AppConfig is much more robust, and would probably be better it the data gets anymore complicated. | [reply] [d/l] [select] |
Re: Configuration File
by Cody Pendant (Prior) on Jul 15, 2003 at 03:13 UTC
|
This seems like exactly the kind of file that the docs for XML::Simple talk about.
Every bit of code is either naturally related to the problem at hand, or else it's an accidental side effect of the fact that you happened to solve the problem using a digital computer.
M-J D | [reply] |
|
Hi there,
I deeply dislike XML for configuration files. Unless your configuration data is extremely complicated, with deeply nested environments, you don't need XML at all; and if so, why are you using such a complex configuration anyway?
A simple win INI style config file is powerful enough to give a lot of structure to a config file, and still easily human readable and editable (see Chris Winters' 'Why I love INI files', his lightning talk this year at YAPC) .
I'm with legLess that YAML is a great option for configuration files.
A different approach that I have successfully used in the past is having a flat key: value(s) file, and provide a module (called Foo::RC.pm) to give it structure by the means of functions (get_router_data(), get_groups_data(), etc...). This has the added advantage of putting all the code (open file, chomp, split, etc...) in one, authoritative place, well documented and maintained, and the ability to merge different configuration files/formats if your system is complex enough that any subsystem just needs a special format for itself. It also makes it more robust before ill-formed config files (all sanity check again performed in just one place) and easily extendable.
As a project meets new requirements during it's development/life time, as it's bound to happen, anyway, your DTD would have to be enhanced to reflect the new functionality, this justs ask for a lot of front-desk thinking about a design you don't yet know. I don't like it at all.
best regards,
-- our $Perl6 is Fantastic;
| [reply] [d/l] |
|
I deeply dislike XML for configuration files. Unless your configuration data is extremely complicated, with deeply nested environments, you don't need XML at all; and if so, why are you using such a complex configuration anyway?
XML files are complicated if YOU make it complicated. Imho, it's the best way to make a portable config file. Parser for xml exists for almost every language. And it is also much fessibile. Change from a simple configuration to a more complex one is a joke with xml. I can't say the same thing for the ini files.
----------
kral
(sorry for my english)
| [reply] |
|
|
| [reply] |
|
I don't think you can rule out XML that easily. It is simple to implement, and provides more scaleability and flexibilty for the future, IMHO.
If you decided you needed to create a more complex config file, for instance having nested groups or the like, it would involve less coding and work to make the change.
Also, if you decided that you wanted to be able to access this file via an api, through another application, or through the web, it gives you a standardized format to work with.
</ajdelore>
| [reply] |
Re: Configuration File
by crackotter (Beadle) on Jul 15, 2003 at 00:26 UTC
|
My mistake, I meant in the group section I want to choose which of the groups to load (will only load one of the variables based on user input). None of the other 'group variables will be loaded. | [reply] |
Re: Configuration File
by tzz (Monk) on Jul 15, 2003 at 13:31 UTC
|
# read the AppConfig docs!
use AppConfig qw/:expand :argcount/;
my $config = AppConfig->new();
# note that variable names are case-insensitive by default
$config->define(
'ROUTER'=> { ARGCOUNT => ARGCOUNT_HASH },
'GROUP1' => { ARGCOUNT => ARGCOUNT_LIST },
'GROUP2' => { ARGCOUNT => ARGCOUNT_LIST },
'GROUP3' => { ARGCOUNT => ARGCOUNT_LIST }, );
$config->file('router.conf');
# now you can access the data
# (untested, but this should give you the idea)
printf ("Router %s is %s\n", $_, $config->ROUTER()->{$_})
foreach keys %{$config->ROUTER()};
printf ("Group %s is %s\n", $_, @{$config->get($_)})
foreach qw/group1 group2 group3/;
| [reply] [d/l] |
|
|