Activator
view release on metacpan or search on metacpan
lib/Activator/Config.pm view on Meta::CPAN
=item *
environment variables
=item *
forced overrides from config files
=item *
merged settings from YAML configuration files
=back
=head1 COMMAND LINE ARGUMENTS
This module allows you to override configuration file settings from
the command line. You can use long or short options using C<'-'> or
C<'--'> notation, allows barewords in any order, and recognizes the
arguments terminator C<'--'>. Also supported are multiple flag
arguments:
#### turn on super verbosity. sets $config->{v} = 2
myscript.pl -v -v
You can specify configured options at the command line for
override:
#### override the configuration file setting for 'foo'
myscript.pl --foo=bar
Note that while YAML configuration (and this module) support deep
structures for configuration, you can only override top level keys
that are scalars using command line arguments and/or environment
variables.
=head2 Reserved Arguments
There are a few reserved command line arguments:
--skip_env : ignore environment variables (EXCEPT $USER)
--project=<> : used to search for the C<E<lt>projectE<gt>.yml> file
--realm=<> : use C<E<lt>realmE<gt>.yml> in config file processing and
consider all command line arguments to be in this realm
--conf_path : colon separated list of directories to search for config files
=head2 Project as a Bareword Argument
There are times where a script takes the project name as a required
bareword argument. For these cases, require that project be the last
argument, and pass a flag to L</get_config()>.
That is, when your script is called like this:
myscript.pl --options <project>
get the config like this:
Activator::Config->get_config( \@ARGV, undef, 1 );
The second argument to L</get_config()> is the realm, so you pass
C<undef> (unless you know the realm you are looking for) to allow the
command line options and environment variables to take affect.
=head1 ENVIRONMENT VARIABLES
Environment variables can be used to act as a default to command line
options, and/or override any top level configuration file key which is
a scalar. The expected format is C<ACT_CONFIG_[key]>. Note that YAML is
case sensitive, so the environment variables must match. Be especially
wary of command shell senstive characters in your YAML keys (like
C<:~E<gt>E<lt>|>).
If you wish to override a key for only a particular realm, you
can insert the realm into the env variable wrapped by double
underscores:
ACT_CONFIG_foo - set 'foo' for default realm
ACT_CONFIG__bar__foo - set 'foo' only for 'bar' realm
The L</Reserved Arguments> listed in the L</COMMAND LINE ARGUMENTS>
section also have corresponding environment variables with only
C<skip_env> being slightly different:
ACT_CONFIG_skip_env : set to 1 to skip, or 0 (or don't set it at all) to
not skip
ACT_CONFIG_project : same as command line argument
ACT_CONFIG_realm : same as command line argument
ACT_CONFIG_conf_path : same as command line argument
=head2 Automatically Imported Environment Variables
Since they tend to be generally useful, the following environment
variables are automatically imported into your configuration:
=over
=item *
HOME
=item *
USER
=back
it is L</FUTURE WORK> to make these cross-platform compatible.
=head1 CONFIGURATION FILES
Currently, you can put your YAML configuration file wherever you like,
but you must set a key inside your configuration files C<conf_path>,
then set the environment variable C<ACT_CONFIG_conf_path> or use the
C<--conf_path> option. It is somewhat wonky the way this currently
works, and it'll get fixed Real Soon Now.
This path behaves the same as a bash shell C<$PATH>, in that you can
set this to one or more colon separated fully qualified path values.
Note that the leftmost path takes precedence when processing config
files.
=head2 Configuration File Heirarchy
In order to facilite the varied ways in which software is developed,
deployed, and used, the following heirarchy lists the configuration
file heirarchy suported from highest precedence to lowest:
$ENV{USER}.yml - user specific settings
<realm>.yml - realm specific settings and defaults
<project>.yml - project specific settings and defaults
org.yml - top level organization settings and defaults
It is up to the script using this module to define what C<project> is,
and up to the project to define what realms exist, which all could
come from any of the command line options, environment variables or
configuration files. All of the above files are optional and will be
ignored if they don't exist.
=head2 Realm Configuration Files
This module supports the concept of realms to allow multiple similar
lib/Activator/Config.pm view on Meta::CPAN
name: Ollie Oliver from Olive Branch, Oklahoma
overrides:
default:
name: Ron Johnson from Ronson, Wisconson
some_realm:
name: Johnny Jammer, the Rhode Island Hammer
C<Activator::Config-E<gt>get_config( \@ARGV )> would return:
$config = { name => 'Ron Johnson from Ronson, Wisconson', }
C<Activator::Config-E<gt>get_config( \@ARGV, 'some_realm' )> would return:
$config = { name => 'Johnny Jammer, the Rhode Island Hammer' }
C<Activator::Config-E<gt>get_config( \@ARGV, 'other_realm' )> would return:
$config = { name => 'Ollie Oliver from Olive Branch, Oklahoma' }
=head2 How to NOT use realms
If you don't need realms for a particular config file (as is often the
case with the C<E<lt>projectE<gt>.yml> file), use the special key
C<act_config_no_realms>. Example:
act_config_no_realms:
this_key: is in the default realm
this_one: too
=head1 CONFIGURATION LOGIC SUMMARY
=over
=item *
All configuration files are read and merged together with higher
precedence configuration files overriding lower precedence on a realm
by realm basis.
If identically named files exist in the C<conf_path> for any level
(user, realm, project, organization), only the first discovered file
is used. Put another way, the leftmost path in the C<conf_path> takes
precedence for any file name conflict.
=item *
The C<default> realm is merged into each realm (I<realm>'s values
taking precedence).
=item *
All C<default> realm environment variables override all values for
each I<realm> (excepting the C<overrides> realm).
=item *
All specific I<realm> environment variables override that realm's values.
=item *
The C<default> realm overrides section is used to override matching
keys in each I<realm>.
=item *
The specific I<realm> overrides section is used to override matching keys
in I<realm>.
=item *
Any command line options given override ALL matching keys for ALL realms.
=item *
# TODO: NOT YET IMPLEMENTED
Perform variable substitution
=back
=head1 METHODS
=cut
sub new {
my ( $pkg ) = @_;
my $self = bless( {
REGISTRY => Activator::Registry->new(),
ARGV_EXTRA => {},
ARGV => undef,
BAREWORDS => undef,
}, $pkg);
$self->_init_StrongSingleton();
return $self;
}
=head2 get_config()
Process command line arguments, environment variables and
configuration files then return a hashref representing the merged
configuration. Recognized configuration items are removed from C<@ARGV>.
Usage:
Activator::Config->get_config( \@ARGV, $realm, $project_is_arg );
C<$realm> is optional (default is 'default'). If undefined, it will be
determined from a command line option or environment variable.
C<$project_is_arg> is optional. Use any true value for this argument
if your script requries the project name as the last bareword
argument.
Examples:
#
# get options for default realm
#
my $config = Activator::Config->get_config( \@ARGV );
#
# get options for 'some' realm, ignoring --realm and ACT_CONFIG_realm
#
lib/Activator/Config.pm view on Meta::CPAN
# ignore barewords
if ( ! defined( $key ) ) {
DEBUG("Ignoring bareword '$arg'");
push @unrec, $arg;
next;
}
# finish up if we find terminator
if ( $key eq '--' ) {
DEBUG("Found arguments terminator --");
unshift @$argv, '--';
last;
}
# TODO: consider supporting realm specific command line arguments
#
# # skip this key if it is for a different realm
# if ( $key =~ /^__(\w+)__(\w+)$/ ) {
# $key_realm = $1;
# $key = $2;
# if( $realm ne $key_realm ) {
# push @unrec, $arg;
# next;
# }
# }
# leave this key in @ARGV if we don't recognize it
if( !exists( $config->{ $key } ) ) {
push @unrec, $arg;
}
# set the value no matter what
$config->{ $key } = $value;
}
unshift @$argv, @unrec;
}
# do variable replacements throughout
sub _var_replace {
my ( $self, $config, $replacements ) = @_;
# Activator::Registry->replace_in_hashref( $config,
}
=head1 DEBUG MODE
Since this module is part of L<Activator>, you can set your
L<Activator::Log> level to DEBUG to see how your C<$config> are
generated.
#### TODO: in the future, there needs to be a 'lint' hash within the
#### realm that says where every variable came from.
=head1 COOKBOOK
#### TODO: these examples are probably complete baloney at this point.
This section gives some examples of how to utilze this module. Each
section below (cleverly) assumes we are writing a Cookbook application
that can fetch recipies from a database.
=head2 End User
Use Case: A user has a CPAN module that provides C<cookbook.pl> to
lookup recipies from a database. The project installs these files:
/etc/cookbook.d/org.yml
/usr/lib/perl5/site-perl/Cookbook.pm
/usr/bin/cookbook.pl
C<org.yml> has the following data:
---
default:
db_name: cookbook
db_user: chef
db_passwd: southpark
The user can run the script as such:
#### list recipes matching beans in the organization's public db
#### using the public account
cookbook.pl lookup beans
#### lookup beans in user's db
cookbook.pl --db_name=my_db \
--db_user=cookie \
--db_passwd=cheflater lookup beans
#### user creates $HOME/$USER.yml
cookbook.pl --conf_file=$HOME/$USER.yaml lookup beans
#### user creates $HOME/.cookbook.d
cookbook.pl lookup beans
=head2 Simple Development
Use Case: developer is working on C<cookbook.pl>. Project directory
looks like:
$HOME/src/Cookbook/lib/Cookbook.pm
$HOME/src/Cookbook/bin/cookbook.pl
$HOME/src/Cookbook/etc/cookbook.d/org.yml
$HOME/src/Cookbook/.cookbook.d/$USER.yml
With these configurations:
org.yml:
---
default:
db_name: cookbook
db_user: chef
db_passwd: southpark
$USER.yml
---
default:
db_name: $USER
( run in 0.895 second using v1.01-cache-2.11-cpan-39bf76dae61 )