File Coverage

blib/lib/XS/Install/Util.pm
Criterion Covered Total %
statement 51 111 45.9
branch 9 44 20.4
condition 4 11 36.3
subroutine 7 11 63.6
pod 0 4 0.0
total 71 181 39.2


line stmt bran cond sub pod time code
1             package
2             XS::Install::Util;
3 11     11   76 use strict;
  11         25  
  11         395  
4 11     11   58 use warnings;
  11         22  
  11         327  
5 11     11   58 use XS::Install::Payload;
  11         47  
  11         266  
6 11     11   71 use Fcntl qw(:flock); # import LOCK_* constants
  11         47  
  11         15268  
7              
8             sub linearize_dependent {
9 1     1 0 96 my $modules = shift;
10 1         4 my %modules = map { $_ => 1 } @$modules;
  8         20  
11             # make list of all dependent
12 1         3 my %dependent;
13 1         4 for my $module (@$modules) {
14 8 50       14 my $info = XS::Install::Payload::binary_module_info($module) or next;
15 8   50     91 my $dependent = $info->{BIN_DEPENDENT} || [];
16 8         14 for my $d_module (@$dependent) {
17 8 100       18 next unless $modules{$d_module};
18 7         9 push @{ $dependent{$module} }, $d_module;
  7         20  
19             }
20             }
21              
22 1         2 my $get_score; $get_score = sub {
23 18     18   25 my $module = shift;
24 18         22 my $score = 1; # initial value for myself
25 18   100     43 my $dependent = $dependent{$module} || [];
26 18         33 for my $d_module (@$dependent) {
27 10         17 $score += $get_score->($d_module);
28             }
29 18         32 return $score;
30 1         61 };
31 1         5 my %scores = map { $_ => $get_score->($_) } @$modules;
  8         13  
32             my @ordered_modules = sort {
33 1 50       33 $scores{$a} <=> $scores{$b}
  14         31  
34             || $a cmp $b
35             } @$modules;
36              
37 1         7 return \@ordered_modules;
38             }
39              
40             sub cmd_sync_bin_deps {
41 0     0 0 0 my $myself = shift @ARGV;
42 0         0 my @modules = @ARGV;
43 0         0 foreach my $module (sort @modules) {
44 0         0 my $file = XS::Install::Payload::binary_module_info_file($module);
45 0         0 my $lock_file = "$file.lock";
46 0         0 my $fh_lock;
47 0 0       0 open $fh_lock, '>', $lock_file or warn "Cannot open $lock_file for writing: $!\n";
48 0 0       0 if ($fh_lock) {
49 0         0 my $ok = eval { flock($fh_lock, LOCK_EX); 1 };
  0         0  
  0         0  
50 0 0       0 warn "Cannot lock $lock_file: $! ($@)\n" unless $ok;
51             }
52              
53 0 0       0 my $info = XS::Install::Payload::binary_module_info($module) or next;
54 0   0     0 my $dependent = $info->{BIN_DEPENDENT} || [];
55 0         0 my %tmp = map {$_ => 1} grep {$_ ne $module} @$dependent;
  0         0  
  0         0  
56 0         0 $tmp{$myself} = 1;
57 0         0 $info->{BIN_DEPENDENT} = linearize_dependent([keys %tmp]);
58 0 0       0 delete $info->{BIN_DEPENDENT} unless @{$info->{BIN_DEPENDENT}};
  0         0  
59 0         0 my $ok = eval { module_info_write($file, $info); 1 };
  0         0  
  0         0  
60 0 0       0 unless ($ok) {
61 0         0 warn("Reverse dependency write failed: $@");
62             }
63 0 0       0 if ($fh_lock) {
64             # possible errors are ignored, as we can do nothing
65 0 0       0 flock($fh_lock, LOCK_UN) && unlink($lock_file);
66             }
67             }
68             }
69              
70             sub cmd_check_dependencies {
71 0     0 0 0 require XS::Install::Deps;
72              
73 0         0 my $objext = shift @ARGV;
74              
75 0         0 my (@inc, @cfiles, @xsfiles);
76 0         0 my $curlist = \@cfiles;
77 0         0 foreach my $arg (@ARGV) {
78 0 0       0 if ($arg =~ s/^-I//) {
    0          
79 0         0 push @inc, $arg;
80             }
81             elsif ($arg eq '-xs') {
82 0         0 $curlist = \@xsfiles;
83             }
84             else {
85 0         0 push @$curlist, $arg;
86             }
87             }
88              
89             my @touch_list = (
90             _check_mtimes(
91             XS::Install::Deps::find_header_deps({
92             files => \@cfiles,
93             headers => ['./'],
94             inc => \@inc,
95             }),
96             sub {
97 0     0   0 my $ofile = shift;
98 0         0 $ofile =~ s/\.[^.]+$//;
99 0         0 $ofile .= $objext;
100 0         0 return $ofile;
101             },
102 0         0 ),
103             _check_mtimes(XS::Install::Deps::find_xsi_deps(\@xsfiles))
104             );
105              
106 0 0       0 if (@touch_list) {
107 0         0 my $now = time();
108 0         0 utime($now, $now, @touch_list);
109             }
110             }
111              
112             sub _check_mtimes {
113 0     0   0 my ($deps, $reference_file_sub) = @_;
114 0         0 my %mtimes;
115             my @touch_list;
116 0         0 foreach my $file (keys %$deps) {
117 0 0       0 my $list = $deps->{$file} or next;
118 0 0       0 my $reference_file = $reference_file_sub ? $reference_file_sub->($file) : $file;
119 0 0       0 my $reference_time = (stat($reference_file))[9] or next;
120 0         0 foreach my $depfile (@$list) {
121 0   0     0 my $mtime = $mtimes{$depfile} ||= (stat($depfile))[9];
122 0 0       0 next if $mtime <= $reference_time;
123             #warn "for file $file dependency $depfile changed";
124 0         0 push @touch_list, $file;
125 0         0 last;
126             }
127             }
128              
129 0         0 return @touch_list;
130             }
131              
132             sub module_info_write {
133 4     4 0 16 my ($file, $info) = @_;
134 4         36 require Data::Dumper;
135 4         14 local $Data::Dumper::Terse = 1;
136 4         24 local $Data::Dumper::Indent = 0;
137 4         36 my $content = Data::Dumper::Dumper($info);
138 4         629 my $restore_mode;
139 4 100       425 if (-e $file) { # make sure we have permissions to write, because perl installs files with 444 perms
140 2         30 my $mode = (stat $file)[2];
141 2 50       13 unless ($mode & 0200) { # if not, temporary enable write permissions
142 0         0 $restore_mode = $mode;
143 0         0 $mode |= 0200;
144 0         0 chmod $mode, $file;
145             }
146             }
147              
148 4         32 my $temp_file = "$file.$$";
149 4 50       350 open my $fh, '>', $temp_file or die "Cannot open $temp_file for writing: $!, binary data could not be written\n";
150 4         58 print $fh $content;
151 4         171 close $fh;
152 4   50     427 rename $temp_file, $file || die("Cannot rename $temp_file to $file\n");
153              
154 4 50       50 chmod $restore_mode, $file if $restore_mode; # restore old perms if we changed it
155             }
156              
157             1;