File Coverage

blib/lib/Module/CheckVersion.pm
Criterion Covered Total %
statement 14 63 22.2
branch 0 28 0.0
condition 0 7 0.0
subroutine 5 6 83.3
pod 1 1 100.0
total 20 105 19.0


line stmt bran cond sub pod time code
1             package Module::CheckVersion;
2              
3 1     1   231463 use 5.010001;
  1         3  
4 1     1   3 use strict;
  1         2  
  1         22  
5 1     1   3 use warnings;
  1         1  
  1         56  
6              
7 1     1   4 use Exporter qw(import);
  1         1  
  1         311  
8              
9             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
10             our $DATE = '2026-04-08'; # DATE
11             our $DIST = 'Module-CheckVersion'; # DIST
12             our $VERSION = '0.091'; # VERSION
13              
14             our @EXPORT_OK = qw(check_module_version);
15              
16             our %SPEC;
17              
18             $SPEC{check_module_version} = {
19             v => 1.1,
20             summary => 'Check module version against the authority (CPAN or elsewhere)',
21             description => <<'MARKDOWN',
22              
23             Designed to be more general and able to provide more information in the future
24             in addition to mere checking of latest version, but checking latest version is
25             currently the only implemented feature.
26              
27             Can handle non-CPAN modules, as long as you put the appropriate `$AUTHORITY` in
28             your modules and create the `Module::CheckVersion::AuthorityScheme::` to
29             handle your authority scheme.
30              
31             MARKDOWN
32             args => {
33             module => {
34             schema => ['str*', match=>qr/\A\w+(::\w+)*\z/],
35             description => <<'MARKDOWN',
36              
37             This routine will try to load the module, and retrieve its `$VERSION`. If
38             loading fails will assume module's installed version is undef.
39              
40             MARKDOWN
41             req => 1,
42             pos => 0,
43             },
44             check_latest_version => {
45             schema => 'bool',
46             default => 1,
47             description => <<'MARKDOWN',
48              
49             If set to 0, will just check installed version.
50              
51             MARKDOWN
52             },
53             default_authority_scheme => {
54             schema => 'str',
55             default => 'cpan',
56             description => <<'MARKDOWN',
57              
58             If a module does not set authority, the default authority scheme will be
59             determined from this setting. The module
60             `Module::CheckVersion::AuthorityScheme::` module is used to implement
61             actual checking.
62              
63             How module's authority is retrieved: First, if `$module->can("AUTHORITY")` then
64             `AUTHORITY` method is called. Otherwise, `$AUTHORITY` package variable is used.
65              
66             Can also be set to undef, in which case when module's authority is not
67             available, will return 412 status.
68              
69             MARKDOWN
70             },
71             },
72             };
73             sub check_module_version {
74 1     1   5 no strict 'refs'; ## no critic: TestingAndDebugging::ProhibitNoStrict
  1         2  
  1         581  
75              
76 0     0 1   my %args = @_;
77 0 0         my $mod = $args{module} or return [400, "Please specify module"];
78 0   0       my $check_latest_version = $args{check_latest_version} // 1;
79 0   0       my $default_authority_scheme = $args{default_authority_scheme} // 'cpan';
80              
81 0           my $res = {};
82              
83             LOAD_MODULE: {
84 0           (my $mod_pm = "$mod.pm") =~ s!::!/!g;
  0            
85 0           eval { require $mod_pm; 1 };
  0            
  0            
86 0 0         $res->{load_module_error} = $@ if $@;
87 0           $res->{installed_version} = do {
88 0 0         if ($mod->can("VERSION")) {
89 0           $mod->VERSION;
90             } else {
91 0           ${"$mod\::VERSION"};
  0            
92             }
93             };
94             } # LOAD_MODULE
95              
96             CHECK_LATEST_VERSION: {
97 0 0         last unless $check_latest_version;
  0            
98              
99 0           my $authority;
100             GET_AUTHORITY: {
101 0 0         if ($mod->can("AUTHORITY")) {
  0            
102 0           $authority = $mod->AUTHORITY;
103             } else {
104 0           $authority = ${"$mod\::AUTHORITY"};
  0            
105             }
106 0 0         unless ($authority) {
107 0 0         $authority = "$default_authority_scheme:"
108             if $default_authority_scheme;
109             }
110 0 0         unless ($authority) {
111 0           return [412, "Can't determine authority for module $mod"];
112             }
113             } # GET_AUTHORITY
114              
115 0 0         return [412, "Module $mod\'s authority '$authority' does not contain scheme"]
116             unless $authority =~ /^(\w+):(.*)/;
117 0           my ($authority_scheme, $authority_content) = ($1, $2);
118              
119 0           my $scheme_mod;
120             LOAD_CHECKER_MODULE: {
121 0           $scheme_mod = "Module::CheckVersion::AuthorityScheme::$authority_scheme";
  0            
122 0           (my $scheme_mod_pm = "$scheme_mod.pm") =~ s!::!/!g;
123 0           require $scheme_mod_pm;
124 0 0         return [500, "Cannot load checker module for authority scheme '$authority_scheme'"]
125             if $@;
126             } # LOAD_CHECKER_MODULE
127              
128 0           my $clvres = &{"$scheme_mod\::check_latest_version"}(
  0            
129             $mod, $authority_scheme, $authority_content);
130              
131 0 0         if ($clvres->[0] == 200) {
132 0           $res->{latest_version} = $clvres->[2];
133             } else {
134 0           $res->{check_latest_version_error} = $clvres->[1];
135             }
136              
137             } # CHECK_LATEST_VERSION
138              
139 0 0 0       if ($res->{installed_version} && $res->{latest_version}) {
140 0           my $cmp = eval {
141             version->parse($res->{installed_version}) <=>
142 0           version->parse($res->{latest_version});
143             };
144 0 0         if ($@) {
145 0           $res->{compare_version_error} = @_;
146 0           $res->{is_latest_version} = undef;
147             } else {
148 0 0         $res->{is_latest_version} = $cmp >= 0 ? 1:0;
149             }
150             }
151              
152 0           [200, "OK", $res];
153             }
154              
155             1;
156             # ABSTRACT: Check module version against the authority (CPAN or elsewhere)
157              
158             __END__