#! /bin/false
$Qgoda::Config::VERSION
=
'0.9.8'
;
use
Qgoda::Util
qw(read_file empty yaml_error merge_data lowercase
safe_yaml_load)
;
my
%processors
;
sub
new {
my
(
$class
,
%args
) =
@_
;
my
$q
= Qgoda->new;
my
$logger
=
$q
->logger(
'config'
);
my
$filename
;
if
(!empty
$args
{filename}) {
$filename
=
$args
{filename};
}
elsif
(-e
'_config.yaml'
) {
$filename
=
'_config.yaml'
;
}
elsif
(-e
'_config.yml'
) {
$filename
=
'_config.yml'
;
}
elsif
(-e
'_config.json'
) {
$filename
=
'_config.json'
;
}
elsif
(!
$q
->getOption(
'no-config'
)) {
$logger
->warning(__
"config file '_config.yaml' not found, "
.
"proceeding with defaults."
);
}
my
$yaml
=
''
;
if
(!empty
$filename
) {
$logger
->info(__x(
"reading configuration from '{filename}'"
,
filename
=>
$filename
));
$yaml
= read_file
$filename
;
if
(!
defined
$yaml
) {
$logger
->fatal(__x(
"cannot read '{filename}': {error}"
,
filename
=>
$filename
,
error
=> $!));
}
}
my
$local_filename
;
if
(-e
'_localconfig.yaml'
) {
$local_filename
=
'_localconfig.yaml'
;
}
elsif
(-e
'_localconfig.yml'
) {
$local_filename
=
'_localconfig.yml'
;
}
elsif
(-e
'_localconfig.json'
) {
$local_filename
=
'_localconfig.json'
;
}
my
$local_yaml
=
''
;
if
(!empty
$local_filename
) {
$logger
->info(__x(
"reading local configuration from '{filename}'"
,
filename
=>
$local_filename
));
$local_yaml
= read_file
$local_filename
;
if
(!
defined
$yaml
) {
$logger
->fatal(__x(
"cannot read '{filename}': {error}"
,
filename
=>
$local_filename
,
error
=> $!));
}
}
my
$jsfile
=
'Qgoda/JavaScript/config.js'
;
require
$jsfile
;
my
$code
= Qgoda::JavaScript::config->code;
my
$node_modules
=
$q
->nodeModules;
my
$js
= Qgoda::JavaScript::Environment->new(
global
=>
$node_modules
,
no_console
=> 1);
my
$schema
= Qgoda::Schema->config;
$js
->vm->set(
schema
=>
$schema
);
$js
->vm->set(
input
=>
$yaml
);
$js
->vm->set(
local_input
=>
$local_yaml
);
$js
->vm->set(
filename
=>
$filename
);
$js
->vm->set(
local_filename
=>
$local_filename
);
$js
->run(
$code
);
my
$exchange
=
$js
->vm->get(
'__perl__'
);
my
$invalid
=
$exchange
->{output}->{errors};
if
(
$invalid
) {
my
(
$filename
,
$errors
) =
@$invalid
;
my
$msg
=
''
;
if
(
ref
$errors
&&
'ARRAY'
eq
ref
$errors
) {
foreach
my
$error
(
@$errors
) {
$msg
.= __x(
"{filename}: CONFIG{dataPath}: "
,
filename
=>
$filename
,
dataPath
=>
$error
->{dataPath});
$msg
.=
"$error->{message}\n"
;
my
$params
=
$error
->{params};
foreach
my
$param
(
keys
%{
$params
|| {}}) {
$msg
.=
"\t$param: $params->{$param}\n"
;
}
}
}
else
{
$msg
=
"$filename: $errors\n"
;
}
die
$msg
;
}
my
$config
=
$js
->vm->get(
'config'
);
my
$self
=
bless
$config
,
$class
;
$config
->{srcdir} = Cwd::abs_path(
''
);
$config
->{paths}->{site} = Cwd::abs_path(
$config
->{paths}->{site});
$config
->{po}->{tt2} = [
$config
->{paths}->{views}]
if
0 == @{
$config
->{po}->{tt2}};
my
$processor_options
=
$schema
->{properties}
->{processors}->{properties}
->{options}->{
default
};
$config
->{processors}->{options} =
merge_data
$processor_options
,
$config
->{processors}->{options};
my
$processor_chains
=
$schema
->{properties}
->{processors}->{properties}
->{chains}->{
default
};
$config
->{processors}->{chains} =
merge_data
$processor_chains
,
$config
->{processors}->{chains};
my
@exclude
= (
'/_*'
,
'.*'
);
my
@exclude_watch
= (
'/_*'
,
'.*'
,
);
my
$viewdir
= File::Spec->abs2rel(
$self
->{paths}->{views});
push
@exclude_watch
,
'!'
. quotestar
$viewdir
if
$viewdir
!~ m{^\.\./};
my
$includedir
= File::Spec->abs2rel(
$self
->{paths}->{includes});
push
@exclude_watch
,
'!'
. quotestar
$includedir
if
$includedir
!~ m{^\.\./};
my
@config_exclude
= @{
$config
->{exclude} || []};
my
@config_exclude_watch
= @{
$config
->{
'exclude-watch'
} ||
$config
->{exclude} || []};
push
@exclude
,
@config_exclude
;
push
@exclude_watch
,
@config_exclude_watch
;
my
$outdir
= File::Spec->abs2rel(
$self
->{outdir},
$self
->{srcdir});
if
(
$outdir
!~ m{^\.\./}) {
push
@exclude
, quotestar
$outdir
, 1;
push
@exclude_watch
, quotestar
$outdir
, 1;
}
unless
(
$args
{raw}) {
$self
->{__q_exclude} = File::Globstar::ListMatch->new(
\
@exclude
,
ignoreCase
=> !
$self
->{
'case-sensitive'
}
);
$self
->{__q_exclude_watch} = File::Globstar::ListMatch->new(
\
@exclude_watch
,
ignoreCase
=> !
$self
->{
'case-sensitive'
}
);
$self
->{defaults} =
$self
->__compileDefaults(
$self
->{defaults});
}
return
$self
;
}
sub
ignorePath {
my
(
$self
,
$path
,
$watch
) =
@_
;
if
(-e
$path
&& (!-f
$path
&& !-d
$path
)) {
return
$self
;
}
return
if
$path
eq
$self
->{srcdir};
my
$relpath
= File::Spec->abs2rel(
$path
,
$self
->{srcdir});
if
(
$watch
) {
return
$self
if
$self
->{__q_exclude_watch}->match(
$relpath
);
}
else
{
return
$self
if
$self
->{__q_exclude}->match(
$relpath
);
}
return
;
}
sub
__compileDefaults {
my
(
$self
,
$rules
) =
@_
;
my
@defaults
;
foreach
my
$rule
(
@$rules
) {
my
$pattern
=
$rule
->{files};
if
(empty
$pattern
) {
$pattern
= [
'*'
];
}
elsif
(!
ref
$pattern
) {
$pattern
= [
$pattern
];
}
$pattern
= File::Globstar::ListMatch->new(
$pattern
,
!
$self
->{
'case-sensitive'
});
push
@defaults
, [
$pattern
,
$rule
->{
values
} || {}];
}
return
\
@defaults
;
}
1;