File Coverage

blib/lib/ExtUtils/Builder/Plan.pm
Criterion Covered Total %
statement 43 64 67.1
branch 11 24 45.8
condition 4 8 50.0
subroutine 11 14 78.5
pod 6 7 85.7
total 75 117 64.1


line stmt bran cond sub pod time code
1             package ExtUtils::Builder::Plan;
2             $ExtUtils::Builder::Plan::VERSION = '0.020';
3 9     9   207367 use strict;
  9         26  
  9         368  
4 9     9   50 use warnings;
  9         18  
  9         449  
5              
6 9     9   50 use Carp ();
  9         21  
  9         159  
7 9     9   43 use Scalar::Util ();
  9         25  
  9         9363  
8              
9             sub new {
10 6     6 0 99 my ($class, %args) = @_;
11             return bless {
12             nodes => $args{nodes} // {}
13 6   50     39 }, $class;
14             }
15              
16             sub node {
17 4     4 1 10 my ($self, $name) = @_;
18 4         15 return $self->{nodes}{$name};
19             }
20              
21             sub nodes {
22 0     0 1 0 my $self = shift;
23 0         0 return @{$self->{nodes}}{ $self->node_names };
  0         0  
24             }
25              
26             sub node_names {
27 5     5 1 4886 my $self = shift;
28 5         12 return sort keys %{ $self->{nodes} };
  5         57  
29             }
30              
31             sub _node_sorter {
32 28     28   76 my ($self, $name, $callback, $seen, $loop) = @_;
33 28 50       88 Carp::croak("$name has a circular dependency, aborting!\n") if exists $loop->{$name};
34 28 50       110 return if $seen->{$name}++;
35 28 50       92 if (my $node = $self->{nodes}{$name}) {
    0          
36 28         66 local $loop->{$name} = 1;
37 28         84 $self->_node_sorter($_, $callback, $seen, $loop) for $node->dependencies;
38 28         73 $callback->($name, $node);
39             } elsif (not -e $name) {
40 0         0 Carp::confess("Node $name doesn't exist")
41             }
42 28         84 return;
43             }
44              
45             sub run {
46 7     7 1 3688 my ($self, $targets, %options) = @_;
47              
48 7 50       60 my @targets = ref($targets) ? @{$targets} : $targets;
  0         0  
49 7         15 my (%seen, %loop);
50             my $run_node = sub {
51 28     28   58 my ($name, $node) = @_;
52 28 100       67 return if $self->_up_to_date($node);
53 21         103 $node->execute(%options);
54 7         34 };
55 7         34 $self->_node_sorter($_, $run_node, \%seen, \%loop) for @targets;
56 7         52 return;
57             }
58              
59             sub _up_to_date {
60 28     28   54 my ($self, $node) = @_;
61 28 100 100     75 return 0 if $node->type eq 'phony' or not -e $node->target;
62 8         19 my $mtime = -M _;
63 8         18 for my $dep_name (sort $node->dependencies) {
64 6 50       17 if (my $dep = $self->{nodes}{$dep_name}) {
65 6 100       32 return 0 unless $dep->newer_than($mtime);
66             } else {
67 0 0 0     0 return 0 unless -e $dep_name && $mtime <= -M _;
68             }
69             }
70 7         23 return 1;
71             }
72              
73             sub merge {
74 0     0 1   my ($self, $other) = @_;
75 0 0         Carp::croak('Right side of merge is not a Plan') if not $other->isa(__PACKAGE__);
76 0           my $double = join ', ', grep { $other->{nodes}{$_} } keys %{ $self->{nodes} };
  0            
  0            
77 0 0         Carp::croak("Found key(s) $double on both sides of merge") if $double;
78 0           my %nodes = (%{ $self->{nodes} }, %{ $other->{nodes} });
  0            
  0            
79 0           return ref($self)->new(nodes => [ values %nodes ]);
80             }
81              
82             sub phonies {
83 0     0 1   my ($self) = @_;
84 0           return sort map { $_->target } grep { $_->phony } values %{ $self->{nodes} };
  0            
  0            
  0            
85             }
86              
87             1;
88              
89             # ABSTRACT: An ExtUtils::Builder Plan
90              
91             __END__