File Coverage

lib/App/Perlbrew/Util.pm
Criterion Covered Total %
statement 74 80 92.5
branch 21 26 80.7
condition 11 17 64.7
subroutine 14 14 100.0
pod 0 9 0.0
total 120 146 82.1


line stmt bran cond sub pod time code
1             package App::Perlbrew::Util;
2 73     73   803107 use strict;
  73         169  
  73         2943  
3 73     73   404 use warnings;
  73         137  
  73         4404  
4 73     73   1378 use 5.008;
  73         278  
5              
6 73     73   428 use Exporter 'import';
  73         360  
  73         116877  
7             our @EXPORT = qw( uniq min editdist files_are_the_same perl_version_to_integer );
8             our @EXPORT_OK = qw(
9             find_similar_tokens
10             looks_like_url_of_skaji_relocatable_perl
11             looks_like_sys_would_be_compatible_with_skaji_relocatable_perl
12             make_skaji_relocatable_perl_url
13             );
14              
15             sub uniq {
16 38     38 0 57 my %seen;
17 38         106 grep { !$seen{$_}++ } @_;
  0         0  
18             }
19              
20             sub min(@) {
21 25179     25179 0 28112 my $m = $_[0];
22 25179         30609 for(@_) {
23 75537 100       114278 $m = $_ if $_ < $m;
24             }
25 25179         38670 return $m;
26             }
27              
28             # straight copy of Wikipedia's "Levenshtein Distance"
29             sub editdist {
30 234     234 0 182796 my @a = split //, shift;
31 234         597 my @b = split //, shift;
32              
33             # There is an extra row and column in the matrix. This is the
34             # distance from the empty string to a substring of the target.
35 234         299 my @d;
36 234         1587 $d[$_][0] = $_ for (0 .. @a);
37 234         1305 $d[0][$_] = $_ for (0 .. @b);
38              
39 234         420 for my $i (1 .. @a) {
40 2458         4172 for my $j (1 .. @b) {
41 26764 100       53990 $d[$i][$j] = ($a[$i-1] eq $b[$j-1] ? $d[$i-1][$j-1]
42             : 1 + min($d[$i-1][$j], $d[$i][$j-1], $d[$i-1][$j-1]));
43             }
44             }
45              
46 234         1779 return $d[@a][@b];
47             }
48              
49             sub files_are_the_same {
50             ## Check dev and inode num. Not useful on Win32.
51             ## The for loop should always return false on Win32, as a result.
52              
53 26     26 0 311155 my @files = @_;
54 26         65 my @stats = map {[ stat($_) ]} @files;
  52         966  
55              
56 26         59 my $stats0 = join " ", @{$stats[0]}[0,1];
  26         142  
57 26         72 for (@stats) {
58 52 100 66     264 return 0 if ((! defined($_->[1])) || $_->[1] == 0);
59 50 100       180 unless ($stats0 eq join(" ", $_->[0], $_->[1])) {
60 14         72 return 0;
61             }
62             }
63 10         53 return 1
64             }
65              
66             sub perl_version_to_integer {
67 209     209 0 398702 my $version = shift;
68              
69 209         442 my @v;
70 209 100       580 if ($version eq 'blead') {
71 1         4 @v = (999,999,999);
72             } else {
73 208         1033 @v = split(/[\.\-_]/, $version);
74             }
75 209 50       574 return undef if @v < 2;
76              
77 209 100       562 if ($v[1] <= 5) {
78 24   100     74 $v[2] ||= 0;
79 24         39 $v[3] = 0;
80             }
81             else {
82 185 50 66     790 $v[3] ||= $v[1] >= 6 ? 9 : 0;
83 185         635 $v[3] =~ s/[^0-9]//g;
84             }
85              
86 209         3503 return $v[1]*1000000 + $v[2]*1000 + $v[3];
87             }
88              
89             sub find_similar_tokens {
90 8     8 0 240098 my ($token, $tokens) = @_;
91 8         14 my $SIMILAR_DISTANCE = 6;
92              
93 51         86 my @similar_tokens = sort { $a->[1] <=> $b->[1] } map {
94 8         22 my $d = editdist( $_, $token );
  228         372  
95 228 100       571 ( ( $d < $SIMILAR_DISTANCE ) ? [$_, $d] : () )
96             } @$tokens;
97              
98 8 100       29 if (@similar_tokens) {
99 6         10 my $best_score = $similar_tokens[0][1];
100 6         15 @similar_tokens = map { $_->[0] } grep { $_->[1] == $best_score } @similar_tokens;
  8         37  
  32         55  
101             }
102              
103 8         110 return \@similar_tokens;
104             }
105              
106             sub looks_like_url_of_skaji_relocatable_perl {
107 68     68 0 293644 my ($str) = @_;
108             # https://github.com/skaji/relocatable-perl/releases/download/5.40.0.0/perl-linux-amd64.tar.gz
109 68         196 my $prefix = "https://github.com/skaji/relocatable-perl/releases/download";
110 68         347 my $version_re = qr/(5\.[0-9][0-9]\.[0-9][0-9]?.[0-9])/;
111 68         217 my $name_re = qr/perl-(linux|darwin)-(amd64|arm64)\.tar\.gz/;
112 68 100       2620 return undef unless $str =~ m{ \Q$prefix\E / $version_re / $name_re }x;
113             return {
114 3         87 url => $str,
115             version => $1,
116             os => $2,
117             arch => $3,
118             original_filename => "perl-$2-$3.tar.gz",
119             };
120             }
121              
122              
123             sub _arch_compat {
124 6     6   39 my ($arch) = @_;
125 6         18 my $compat = {
126             x86_64 => "amd64",
127             i386 => "amd64",
128             };
129 6   66     52 return $compat->{$arch} || $arch;
130             }
131              
132             sub looks_like_sys_would_be_compatible_with_skaji_relocatable_perl {
133 5     5 0 11079 my ($detail, $sys) = @_;
134              
135             return (
136             ($detail->{os} eq $sys->os)
137 5   100     24 && (_arch_compat($detail->{arch}) eq _arch_compat($sys->arch))
138             );
139             }
140              
141             sub make_skaji_relocatable_perl_url {
142 62     62 0 188 my ($str, $sys) = @_;
143 62 50       218 if ($str =~ m/\Askaji-relocatable-perl-(5\.[0-9][0-9]\.[0-9][0-9]?.[0-9])\z/) {
144 0         0 my $version = $1;
145 0         0 my $os = $sys->os;
146 0         0 my $arch = $sys->arch;
147 0 0 0     0 $arch = "amd64" if $arch eq 'x86_64' || $arch eq 'i386';
148              
149 0         0 return "https://github.com/skaji/relocatable-perl/releases/download/$version/perl-$os-$arch.tar.gz";
150             }
151 62         267 return undef;
152             }
153              
154             1;