File Coverage

blib/lib/Git/Version/Compare.pm
Criterion Covered Total %
statement 57 57 100.0
branch 12 12 100.0
condition 14 26 53.8
subroutine 10 10 100.0
pod 2 2 100.0
total 95 107 88.7


line stmt bran cond sub pod time code
1             package Git::Version::Compare;
2             $Git::Version::Compare::VERSION = '1.003';
3 4     4   78942 use strict;
  4         6  
  4         136  
4 4     4   18 use warnings;
  4         6  
  4         163  
5 4     4   20 use Exporter;
  4         5  
  4         189  
6 4     4   20 use Carp;
  4         6  
  4         300  
7              
8 4     4   2309 use namespace::clean;
  4         65826  
  4         20  
9              
10             my @ops = qw( lt gt le ge eq ne );
11              
12             our @ISA = qw(Exporter);
13             our @EXPORT_OK = ( looks_like_git => map "${_}_git", cmp => @ops );
14             our %EXPORT_TAGS = ( ops => [ map "${_}_git", @ops ], all => \@EXPORT_OK );
15              
16             # A few versions have two tags, or non-standard numbering:
17             # - the left-hand side is what `git --version` reports
18             # - the right-hand side is an internal canonical name
19             #
20             # We turn versions into strings, so we can use the fast `eq` and `gt`.
21             # The 6 elements are integers padded with 0:
22             # - the 4 parts of the dotted version (padded with as many .0 as needed)
23             # - '.000' if not an RC, or '-xxx' if an RC (- sorts before . in ascii)
24             # - the number of commits since the previous tag (for dev versions)
25             #
26             # The special cases are pre-computed below, the rest is computed as needed.
27             my %version_alias = (
28             '0.99.7a' => '00.99.07.01.00.0000',
29             '0.99.7b' => '00.99.07.02.00.0000',
30             '0.99.7c' => '00.99.07.03.00.0000',
31             '0.99.7d' => '00.99.07.04.00.0000',
32             '0.99.8a' => '00.99.08.01.00.0000',
33             '0.99.8b' => '00.99.08.02.00.0000',
34             '0.99.8c' => '00.99.08.03.00.0000',
35             '0.99.8d' => '00.99.08.04.00.0000',
36             '0.99.8e' => '00.99.08.05.00.0000',
37             '0.99.8f' => '00.99.08.06.00.0000',
38             '0.99.8g' => '00.99.08.07.00.0000',
39             '0.99.9a' => '00.99.09.01.00.0000',
40             '0.99.9b' => '00.99.09.02.00.0000',
41             '0.99.9c' => '00.99.09.03.00.0000',
42             '0.99.9d' => '00.99.09.04.00.0000',
43             '0.99.9e' => '00.99.09.05.00.0000',
44             '0.99.9f' => '00.99.09.06.00.0000',
45             '0.99.9g' => '00.99.09.07.00.0000',
46             '0.99.9h' => '00.99.09.08.00.0000', # 1.0.rc1
47             '1.0.rc1' => '00.99.09.08.00.0000',
48             '0.99.9i' => '00.99.09.09.00.0000', # 1.0.rc2
49             '1.0.rc2' => '00.99.09.09.00.0000',
50             '0.99.9j' => '00.99.09.10.00.0000', # 1.0.rc3
51             '1.0.rc3' => '00.99.09.10.00.0000',
52             '0.99.9k' => '00.99.09.11.00.0000',
53             '0.99.9l' => '00.99.09.12.00.0000', # 1.0.rc4
54             '1.0.rc4' => '00.99.09.12.00.0000',
55             '0.99.9m' => '00.99.09.13.00.0000', # 1.0.rc5
56             '1.0.rc5' => '00.99.09.13.00.0000',
57             '0.99.9n' => '00.99.09.14.00.0000', # 1.0.rc6
58             '1.0.rc6' => '00.99.09.14.00.0000',
59             '1.0.0a' => '01.00.01.00.00.0000',
60             '1.0.0b' => '01.00.02.00.00.0000',
61             );
62              
63             sub looks_like_git {
64 169     169 1 13541 return scalar $_[0] =~
65             /^(?:v|git\ version\ )? # prefix
66             [0-9]+(?:[.-](?:0[ab]?|[1-9][0-9a-z]*|[a-zA-Z]+))* # x.y.z.*
67             (?:[.-]?rc[0-9]+)? # rc
68             (?:[.-](GIT|[1-9][0-9]*[.-]g[A-Fa-f0-9]+))? # devel
69             (?:\ .*)? # comment
70             $/x;
71             }
72              
73             sub _normalize {
74 106     106   8925 my ($v) = @_;
75 106 100       206 return undef if !defined $v;
76              
77             # minimal consistency check
78 105 100       158 croak "$v does not look like a Git version" if !looks_like_git($v);
79              
80             # reformat git.git tag names, output of `git --version`
81 104         400 $v =~ s/^v|^git version |\.msysgit.*|[\012\015]+\z//g;
82 104         152 $v =~ y/-/./;
83 104         122 $v =~ s/0rc/0.rc/;
84 104         234 ($v) = split / /, $v; # drop anything after the version
85 104 100       268 return $version_alias{$v} if defined $version_alias{$v};
86              
87 97         191 my @v = split /\./, $v;
88 97         102 my ( $r, $c ) = ( 0, 0 );
89              
90             # commit count since the previous tag
91 97 100       157 ($c) = ( 1, splice @v, -1 ) if $v[-1] eq 'GIT'; # before 1.4
92 97 100       225 ($c) = splice @v, -2 if substr( $v[-1], 0, 1 ) eq 'g'; # after 1.4
93              
94             # release candidate number
95 97 100       176 ($r) = splice @v, -1 if substr( $v[-1], 0, 2 ) eq 'rc';
96 97   66     142 $r &&= do { $r =~ s/rc//; sprintf '-%02d', $r };
  21         41  
  21         93  
97              
98 97   100     1470 join( '.', map sprintf( '%02d', $_ ), ( @v, 0, 0, 0 )[ 0 .. 3 ] )
99             . ( $r || '.00' )
100             . sprintf( '.%04d', $c );
101             }
102              
103             for my $op (@ops) {
104 4     4   3554 no strict 'refs';
  4         7  
  4         653  
105 1669   33 1669   2614 *{"${op}_git"} = eval << "OP";
  1669   33     8239  
  1669   33     8827  
  1669   66     2915  
  1669   66     8643  
  1669   33     8679  
  1669         2667  
  1669         8540  
  1669         8552  
  1669         327260  
  1669         9182  
  1669         8679  
  1670         3063  
  1670         8286  
  1669         8021  
  1669         2976  
  1669         8042  
  1669         8381  
106             sub {
107             my ( \$v1, \$v2 ) = \@_;
108             \$_ = \$version_alias{\$_} ||= _normalize( \$_ ) for \$v1, \$v2;
109             return \$v1 $op \$v2;
110             }
111             OP
112             }
113              
114             sub cmp_git ($$) {
115 2431     2431 1 4007 my ( $v1, $v2 ) = @_;
116 2431   66     10858 $_ = $version_alias{$_} ||= _normalize( $_ ) for $v1, $v2;
117 2431         9557 return $v1 cmp $v2;
118             }
119              
120             1;
121              
122             __END__