our
$VERSION
=
'0.002'
;
sub
new {
my
$class
=
shift
;
my
%args
=
@_
;
my
$struct
= {
_main_options
=> [],
_general_options
=> [],
_special_options
=> {},
_final_options
=> {},
};
for
my
$known
(
keys
%$struct
) {
(
my
$key
=
$known
) =~ s/^_//;
$struct
->{
$known
} =
delete
$args
{
$key
}
if
exists
$args
{
$key
};
}
my
$self
=
bless
$struct
,
$class
;
$self
->process_options();
return
$self
;
}
sub
configfile_option {
my
$class
=
shift
;
return
Test::Smoke::App::AppOption->new(
name
=>
'configfile'
,
option
=>
'config|c=s'
,
helptext
=>
"Set the name/prefix of the configfile\n"
,
);
}
sub
verbose_option {
my
$class
=
shift
;
return
Test::Smoke::App::AppOption->new(
name
=>
'verbose'
,
option
=>
'v=i'
,
allow
=> [0, 1, 2],
default
=> 0,
helptext
=>
'Set verbosity level.'
,
);
}
sub
show_config_option {
return
Test::Smoke::App::AppOption->new(
name
=>
'show_config'
,
option
=>
'show-config'
,
helptext
=>
"Show all about config vars."
,
);
}
sub
process_options {
my
$self
=
shift
;
$self
->{_opt_collection} = Test::Smoke::App::AppOptionCollection->new();
$self
->_pre_process_options();
$self
->_get_options();
$self
->_post_process_options();
return
$self
;
}
sub
option {
my
$self
=
shift
;
my
(
$option
) =
@_
;
my
$opts
=
$self
->final_options;
if
(
exists
$opts
->{
$option
}) {
my
$is_main
=
grep
$_
->name eq
$option
, @{
$self
->main_options};
return
$opts
->{
$option
}
if
$is_main
;
my
$is_general
=
grep
$_
->name eq
$option
, @{
$self
->general_options};
return
$opts
->{
$option
}
if
$is_general
;
for
my
$mainopt
(@{
$self
->main_options}) {
my
$type
=
$opts
->{
$mainopt
->name};
my
$specials
=
$self
->special_options->{
$type
};
my
$is_special
=
grep
$_
->name eq
$option
,
@$specials
;
return
$opts
->{
$option
}
if
$is_special
;
}
croak(
"Option '$option' is not valid."
);
}
croak(
"Invalid option '$option'"
);
}
sub
_find_option {
my
$self
=
shift
;
my
(
$option
) =
@_
;
my
(
$oo
) =
grep
$_
->name eq
$option
, @{
$self
->main_options};
return
$oo
if
$oo
;
(
$oo
) =
grep
$_
->name eq
$option
, @{
$self
->general_options};
return
$oo
if
$oo
;
for
my
$mo
(@{
$self
->main_options}) {
my
$type
=
$self
->final_options->{
$mo
->name};
my
$specials
=
$self
->special_options->{
$type
};
(
$oo
) =
grep
$_
->name eq
$option
,
@$specials
;
return
$oo
if
$oo
;
}
return
;
}
sub
options {
my
$self
=
shift
;
my
%options
;
for
my
$opt
(@{
$self
->main_options}) {
my
$type
=
$self
->option(
$opt
->name);
$options
{
$opt
->name} =
$type
;
my
$specials
=
$self
->special_options->{
$type
};
for
my
$opt
(
@$specials
) {
$options
{
$opt
->name} =
$self
->option(
$opt
->name);
}
}
for
my
$opt
(@{
$self
->general_options }) {
next
if
$opt
->name =~ /^(?:help|show_config)$/;
$options
{
$opt
->name} =
$self
->option(
$opt
->name);
}
return
%options
;
}
sub
_pre_process_options {
my
$self
=
shift
;
unshift
@{
$self
->general_options},
$self
->configfile_option;
push
@{
$self
->general_options},
$self
->show_config_option;
push
@{
$self
->general_options},
$self
->verbose_option;
for
my
$opt
(@{
$self
->general_options}) {
$self
->opt_collection->add(
$opt
);
}
for
my
$opt
(
sort
{
$a
->name cmp
$b
->name} @{
$self
->main_options}) {
$self
->opt_collection->add_helptext(
"\n"
);
$self
->opt_collection->add(
$opt
);
for
my
$special
(
sort
{
lc
(
$a
) cmp
lc
(
$b
)} @{
$opt
->allow}) {
$self
->opt_collection->add_helptext(
sprintf
(
"\nOptions for '%s':\n"
,
$special
)
);
my
$specials
=
$self
->special_options->{
$special
};
for
my
$thisopt
(
@$specials
) {
$self
->opt_collection->add(
$thisopt
);
}
}
}
my
$helptext
=
$self
->opt_collection->helptext;
my
$help_option
= Test::Smoke::App::AppOption->new(
name
=>
'help'
,
option
=>
'h'
,
default
=>
sub
{
print
"Usage: $0 [options]\n\n$helptext"
;
exit
(0);
},
helptext
=>
'This message.'
,
);
push
@{
$self
->general_options},
$help_option
;
$self
->opt_collection->add(
$help_option
);
%{
$self
->{_dft_options}} = %{
$self
->opt_collection->options_with_default};
}
sub
_get_options {
my
$self
=
shift
;
%{
$self
->{_cli_options}} = %{
$self
->opt_collection->options_for_cli};
@{
$self
->{_ARGV}} =
@ARGV
;
Getopt::Long::Configure(
'no_ignore_case'
);
GetOptions(
$self
->cli_options,
@{
$self
->opt_collection->options_list },
);
}
sub
_post_process_options {
my
$self
=
shift
;
$self
->_obtain_config_file;
%{
$self
->final_options} = %{
$self
->cli_options};
$self
->final_options(
{
%{
$self
->opt_collection->all_options},
%{
$self
->dft_options},
%{
$self
->from_configfile},
%{
$self
->cli_options},
}
);
my
@errors
;
my
%check_options
=
$self
->options;
for
my
$opt
(
keys
%check_options
) {
my
$oo
=
$self
->_find_option(
$opt
);
my
$value
=
$self
->final_options->{
$opt
};
$value
=
'<undef>'
if
!
defined
$value
;
push
(
@errors
,
sprintf
(
"Invalid value '%s' for option '%s'"
,
$value
,
$opt
)
)
if
!
$oo
->allowed(
$self
->final_options->{
$opt
});
}
if
(
@errors
) {
print
"$_\n"
for
@errors
;
exit
(1);
}
if
(
$self
->final_options->{show_config}) {
print
"Show configuration requested:\n"
;
print
sprintf
(
" %-20s| %s\n"
,
'Option'
,
'Value'
);
print
"----------------------+--------------------------------------------\n"
;
my
%options
=
$self
->options;
for
my
$opt
(
sort
keys
%options
) {
printf
" %-20s| %s\n"
,
$opt
,
$self
->_show_option_value(
$opt
) ||
'?'
;
}
exit
(0);
}
}
sub
_show_option_value {
my
$self
=
shift
;
my
(
$option_name
) =
@_
;
return
serialise(
$self
->option(
$option_name
) );
}
sub
_obtain_config_file {
my
$self
=
shift
;
$self
->{_from_configfile} = {};
my
$cf_name
=
$self
->cli_options->{
'configfile'
};
return
if
!
$cf_name
;
if
(!-f
$cf_name
) {
for
my
$ext
(
qw/_config .config/
) {
if
(-f
"${cf_name}${ext}"
) {
$cf_name
.=
$ext
;
last
}
}
}
if
(-f
$cf_name
) {
my
$abs_cf
=
$self
->cli_options->{
'configfile'
} = abs_path(
$cf_name
);
our
$conf
;
local
$conf
;
delete
$INC
{
$abs_cf
};
eval
{
local
$^W;
require
$abs_cf
};
$self
->{_configfile_error} = $@;
%{
$self
->from_configfile} = %{
$conf
|| {} };
delete
$INC
{
$abs_cf
};
$self
->from_configfile->{verbose} =
delete
(
$self
->from_configfile->{v})
if
exists
$self
->from_configfile->{v};
}
else
{
$self
->{_configfile_error} =
"Could not find a configfile for '$cf_name'."
;
}
}
1;