in reply to command line args - a chicken and egg problem

If you can live with a modification of your command-line argument rules, you can make this all pretty simple.

Rule 2b: The configuration file overrides command-line options occuring before it is specified, is overridden by those occuring after.

With that, you only need to process the config file as soon as it is specified. To get the behavior you wanted, your user would just have to name the config file first.

After Compline,
Zaxo

  • Comment on Re: command line args - a chicken and egg problem

Replies are listed 'Best First'.
Re^2: command line args - a chicken and egg problem
by sfink (Deacon) on Apr 12, 2006 at 06:00 UTC
    That works nicely unless you have a default config file. You can't process it as the zeroth argument, because it shouldn't be read at all if a config file option is given on the command line. And it can't be processed conditionally after the command-line args because then it would override the command line.

    I have run into this several times too, but I don't remember what I ended up with. Probably something different and slightly wrong each time. I guess you could do something like:

    my %opts = ( 'config' => 'default.config', 'other1' => 'default1', 'other2' => 'default2' ); %opts = (%opts, process_command_line()); %opts = (read_config_file($opts{config}), %opts);
    which might be better spelled
    my %defaults = ( 'other1' => 'default1', 'other2' => 'default2' ); my %from_cmdline = process_command_line(); my $config = $from_cmdline{config} || "default.config"; my %from_config = read_config_file($config); my %opts = (%defaults, %from_config, %from_cmdline);
    I wouldn't use either, because I always use Getopt::Long. So perhaps:
    my %defaults = ( param1 => 'default1', param2 => 'default2' ); my $config = 'default.config'; GetOptions("config|c=s" => \$config, "param1=s" => \$opt{param1}, "param2=s" => \$opt{param2}); %defaults = (%defaults, read_config_file($config)); while (my ($param, $value) = each %defaults) { $opt{$param} = $value unless defined $opt{$param}; }
    which doesn't feel very satisfying. Maybe it would be better to use Zaxo's rule 2b and fold them together?
    my %opts = ( param1 => 'default1', param2 => 'default2' ); my $use_default_config = 1; GetOptions("config|c=s" => sub { my ($param, $value) = @_; $use_default_config = 0; read_config_file(\%opt, $value); }, "param1=s" => \$opt{param1}, "param2=s" => \$opt{param2}); read_config_file(\%opt, 'default.config') if $use_default_config;
    Feels about right.

    Update: I just read through the POD for AppConfig. I agree; it sounds really nice! But it looks like it doesn't expose enough to implement what you want. Seems like a good opportunity to submit a patch.