join '/', @res;
}
-### Private OO API
-our %req_unavailability_cache;
-
-# this method is just a lister and envvar/metadata checker - it does not try to load anything
-my $processed_groups = {};
-sub _groups_to_reqs {
- my ($self, $groups) = @_;
-
- $groups = [ $groups || () ]
- unless ref $groups eq 'ARRAY';
-
- croak "@{[ (caller(1))[3] ]}() expects a requirement group name or arrayref of group names"
- unless @$groups;
-
- my $ret = {
- modreqs => {},
- modreqs_fully_documented => 1,
- };
+# Expand includes from a random group in a specific order:
+# nonvariable groups first, then their includes, then the variable groups,
+# then their includes.
+# This allows reliably marking the rest of the mod reqs as variable (this is
+# also why variable includes are currently not allowed)
+sub __expand_includes {
+ my ($groups, $seen) = @_;
+
+ # !! DIFFERENT !! behavior and return depending on invocation mode
+ # (easier to recurse this way)
+ my $is_toplevel = $seen
+ ? 0
+ : !! ($seen = {})
+ ;
- for my $group ( grep { ! $processed_groups->{$_} } @$groups ) {
+ my ($res_per_type, $missing_envvars);
- $group =~ /\A [A-Z_a-z][0-9A-Z_a-z]* \z/x
- or croak "Invalid requirement group name '$group': only ascii alphanumerics and _ are allowed";
+ # breadth-first evaluation, with non-variable includes on top
+ for my $g (@$groups) {
- croak "Requirement group '$group' is not defined" unless defined $dbic_reqs->{$group};
+ croak "Invalid requirement group name '$g': only ascii alphanumerics and _ are allowed"
+ if $g !~ /\A [A-Z_a-z][0-9A-Z_a-z]* \z/x;
- my $group_reqs = $dbic_reqs->{$group}{req};
+ my $r = $dbic_reqs->{$g}
+ or croak "Requirement group '$g' is not defined";
- # sanity-check
- for (keys %$group_reqs) {
+ # always do this check *before* the $seen check
+ croak "Group '$g' with variable effective_modreqs can not be specified as an 'include'"
+ if ( $r->{env} and ! $is_toplevel );
- $_ =~ /\A [A-Z_a-z][0-9A-Z_a-z]* (?:::[0-9A-Z_a-z]+)* \z /x
- or croak "Requirement '$_' in group '$group' is not a valid module name";
+ next if $seen->{$g}++;
- # !!!DO NOT CHANGE!!!
- # remember - version.pm may not be available on the system
- croak "Requirement '$_' in group '$group' specifies an invalid version '$group_reqs->{$_}' (only plain non-underscored floating point decimals are supported)"
- if ( ($group_reqs->{$_}||0) !~ / \A [0-9]+ (?: \. [0-9]+ )? \z /x );
- }
+ my $req_type = 'static';
- # check if we have all required envvars if such names are defined
- my ($some_envs_required, $some_envs_missing);
- if (my @e = @{$dbic_reqs->{$group}{env} || [] }) {
+ if ( my @e = @{$r->{env}||[]} ) {
- croak "Unexpected 'env' attribute under group '$group' (only allowed in test_* groups)"
- unless $group =~ /^test_/;
+ croak "Unexpected 'env' attribute under group '$g' (only allowed in test_* groups)"
+ unless $g =~ /^test_/;
- croak "Unexpected *odd* list in 'env' under group '$group'"
+ croak "Unexpected *odd* list in 'env' under group '$g'"
if @e % 2;
- my @group_envnames_list;
-
# deconstruct the whole thing
+ my (@group_envnames_list, $some_envs_required, $some_required_missing);
while (@e) {
push @group_envnames_list, my $envname = shift @e;
$some_envs_required ||= 1;
- $some_envs_missing ||= (
+ $some_required_missing ||= (
! defined $ENV{$envname}
or
! length $ENV{$envname}
);
}
- croak "None of the envvars in group '$group' declared as required, making the requirement moot"
+ croak "None of the envvars in group '$g' declared as required, making the requirement moot"
unless $some_envs_required;
- push @{$ret->{missing_envvars}}, \@group_envnames_list if $some_envs_missing;
+ if ($some_required_missing) {
+ push @{$missing_envvars->{$g}}, \@group_envnames_list;
+ $req_type = 'variable';
+ }
+ }
+
+ push @{$res_per_type->{"base_${req_type}"}}, $g;
+
+ if (my $i = $dbic_reqs->{$g}{include}) {
+ $i = [ $i ] unless ref $i eq 'ARRAY';
+
+ croak "Malformed 'include' for group '$g': must be another existing group name or arrayref of existing group names"
+ unless @$i;
+
+ push @{$res_per_type->{"incs_${req_type}"}}, @$i;
}
+ }
+
+ my @ret = map {
+ @{ $res_per_type->{"base_${_}"} || [] },
+ ( $res_per_type->{"incs_${_}"} ? __expand_includes( $res_per_type->{"incs_${_}"}, $seen ) : () ),
+ } qw(static variable);
+
+ return ! $is_toplevel ? @ret : do {
+ my $rv = {};
+ $rv->{$_} = {
+ idx => 1 + keys %$rv,
+ missing_envvars => $missing_envvars->{$_},
+ } for @ret;
+ $rv;
+ };
+}
+
+### Private OO API
+our %req_unavailability_cache;
+
+# this method is just a lister and envvar/metadata checker - it does not try to load anything
+sub _groups_to_reqs {
+ my ($self, $groups) = @_;
+
+ $groups = [ $groups || () ]
+ unless ref $groups eq 'ARRAY';
+
+ croak "@{[ (caller(1))[3] ]}() expects a requirement group name or arrayref of group names"
+ unless @$groups;
- # get the reqs for includes if any
- my $inc_reqs;
- if (my $incs = $dbic_reqs->{$group}{include}) {
- $incs = [ $incs ] unless ref $incs eq 'ARRAY';
+ my $ret = {
+ modreqs => {},
+ modreqs_fully_documented => 1,
+ };
- croak "Malformed 'include' for group '$group': must be another existing group name or arrayref of existing group names"
- unless @$incs;
+ my $all_groups = __expand_includes($groups);
- local $processed_groups->{$group} = 1;
+ for my $group (sort { $all_groups->{$a}{idx} <=> $all_groups->{$b}{idx} } keys %$all_groups ) {
- my $subreqs = $self->_groups_to_reqs($incs);
+ my $group_reqs = $dbic_reqs->{$group}{req};
- croak "Includes with variable effective_modreqs not yet supported"
- if $subreqs->{effective_modreqs_differ};
+ # sanity-check
+ for (keys %$group_reqs) {
- $inc_reqs = $subreqs->{modreqs};
+ $_ =~ /\A [A-Z_a-z][0-9A-Z_a-z]* (?:::[0-9A-Z_a-z]+)* \z /x
+ or croak "Requirement '$_' in group '$group' is not a valid module name";
+
+ # !!!DO NOT CHANGE!!!
+ # remember - version.pm may not be available on the system
+ croak "Requirement '$_' in group '$group' specifies an invalid version '$group_reqs->{$_}' (only plain non-underscored floating point decimals are supported)"
+ if ( ($group_reqs->{$_}||0) !~ / \A [0-9]+ (?: \. [0-9]+ )? \z /x );
+ }
+ if (my $e = $all_groups->{$group}{missing_envvars}) {
+ push @{$ret->{missing_envvars}}, @$e;
}
# assemble into the final ret
for my $type (
'modreqs',
- $some_envs_missing ? () : 'effective_modreqs'
+ ( $ret->{missing_envvars} ? () : 'effective_modreqs' ),
) {
- for my $req_bag ($group_reqs, $inc_reqs||()) {
+ for my $req_bag ($group_reqs) {
for my $mod (keys %$req_bag) {
$ret->{$type}{$mod} = $req_bag->{$mod}||0 if (
}
}
- $ret->{effective_modreqs_differ} ||= !!$some_envs_missing;
-
$ret->{modreqs_fully_documented} &&= !!$dbic_reqs->{$group}{pod};
$ret->{release_testing_mandatory} ||= !!$dbic_reqs->{$group}{release_testing_mandatory};