List your dist's prereqs where newer versions have become available

I've got quite a few CPAN distributions that require one another, and it's gotten to the point that it's very easy to forget to bump prereq versions before uploading a new release to the CPAN.

As a stopgap, I wrote Module::CheckDep::Version (may not be indexed yet). What this module does is using MetaCPAN::Client, fetches all distributions by author, pulls out all prerequisite distributions and the version of it that your distribution has listed, checks if there's a newer version of it, and lists out the ones that need a bump in the prereq's version.

Update: I've updated the distribution (v0.05) to install a binary, checkdep, so that you don't have to write your own to use the library:

Usage: checkdep PAUSEID [options]

-a|--all        Work on all dependencies, not just the author's
-m|--module     String; Work only on a specific distribution. (eg: Mock::Sub)
-z|--zero       Include dependencies listed with a version of zero
-h|--help       Display this help screen

/update

The most basic of runs takes a single parameter, a PAUSE ID (CPAN username), and lists the discrepancies of prereq version mismatches for that author's own prereq distributions only. As well, if the author has any prerequisites listed with a version of 0 (zero, meaning any version will do) we skip them by default (ie. they don't show up in the output; see below how to change this behaviour). Here's an example of that:

use warnings;
use strict;

use Module::CheckDep::Version qw(check_deps);

check_deps('STEVEB');

Output:

RPi-I2C:
    WiringPi::API:
        2.3609 -> 2.3612

App-RPi-EnvUI:
    Logging::Simple:
        1.01 -> 1.04
    WiringPi::API:
        1.04 -> 2.3612
    RPi::DHT11:
        1.01 -> 1.02
    RPi::WiringPi::Constant:
        0.02 -> 1.00

RPi-DAC-MCP4922:
    RPi::WiringPi::Constant:
        0.02 -> 1.00
    WiringPi::API:
        2.3608 -> 2.3612

Wrap-Sub:
    Devel::Examine::Subs:
        1.63 -> 1.69

RPi-WiringPi:
    RPi::LCD:
        2.3601 -> 2.3603
    RPi::I2C:
        2.3602 -> 2.3603

Devel-Trace-Subs:
    Mock::Sub:
        1.01 -> 1.07
    Devel::Examine::Subs:
        1.61 -> 1.69

Devel-Examine-Subs:
    Mock::Sub:
        1.06 -> 1.07

RPi-DigiPot-MCP4XXXX:
    WiringPi::API:
        2.3608 -> 2.3612
    RPi::WiringPi::Constant:
        0.02 -> 1.00

RPi-SPI:
    WiringPi::API:
        2.3608 -> 2.3612

RPi-ADC-MCP3008:
    WiringPi::API:
        2.3608 -> 2.3612
    RPi::WiringPi::Constant:
        0.02 -> 1.00

RPi-Pin:
    WiringPi::API:
        2.3609 -> 2.3612

RPi-BMP180:
    WiringPi::API:
        2.3608 -> 2.3612
    RPi::WiringPi::Constant:
        0.02 -> 1.00

Test-BrewBuild:
    Test::BrewBuild::Plugin::Author:
        0.02 -> 0.03
    Plugin::Simple:
        0.06 -> 0.07
    Logging::Simple:
        0.07 -> 1.04

File-Edit-Portable:
    Mock::Sub:
        1.06 -> 1.07

Using the all => 1 param, we'll check against all prereqs, the author's own ones and those of any other author. If it's listed as a dependency, we'll check it. Again, we skip prereqs with a listed value of zero:

check_deps('STEVEB', all => 1);

Example (snipped) output:

RPi-LCD:
    ExtUtils::MakeMaker:
        6.72 -> 7.30

Bit-Manip-PP:
    ExtUtils::MakeMaker:
        7.1 -> 7.30

Test-BrewBuild:
    Test::BrewBuild::Plugin::Author:
        0.02 -> 0.03
    Logging::Simple:
        0.07 -> 1.04
    Plugin::Simple:
        0.06 -> 0.07

App-CopyrightImage:
    Image::ExifTool:
        10.2 -> 10.55

You can look up only a single distribution instead of listing all of them (this works with all => 1 as well):

check_deps('STEVEB', module => 'RPi::WiringPi');

Output:

RPi-WiringPi:
    RPi::I2C:
        2.3602 -> 2.3603
    RPi::LCD:
        2.3601 -> 2.3603

You can request the data back (a hashref of hashrefs) instead of displaying it to STDOUT:

my $data = check_deps('STEVEB', return => 1);

You can send in a code reference to handle the data within the module instead of getting it returned or printed. This sub can do anything you want it to. Your sub gets passed a single parameter, a hashref of hashrefs, same as with the return functionality:

check_deps('STEVEB', handler => \&my_handler);

sub my_handler {
    my $data = shift;

    for my $dist (keys %$data){
        for my $dep (keys %{ $data->{$dist} }){
            my $dep_ver = $data->{$dist}{$dep}{dep_ver};
            my $cur_ver = $data->{$dist}{$dep}{cur_ver};

            print "$dist has dep $dep with listed ver $dep_ver " .
                    "and updated ver $cur_ver\n";
        }
    }
}

Sample output:

App-RPi-EnvUI has dep Async::Event::Interval with listed ver 0.00 and updated ver 0.03
Devel-Trace-Subs has dep Devel::Examine::Subs with listed ver 1.61 and updated ver 1.69
Devel-Trace-Subs has dep Mock::Sub with listed ver 1.01 and updated ver 1.07
RPi-WiringPi has dep RPi::LCD with listed ver 2.3601 and updated ver 2.3603
RPi-WiringPi has dep RPi::I2C with listed ver 2.3602 and updated ver 2.3603

Lastly, how do you include all prereqs even if the listed wanted version is zero?:

check_deps('STEVEB', ignore_any => 0);

I was going to hook this into an automation script using other tools I have written, but I just don't have the time. Just knowing what needs to be updated is fine for me for now.

As always, have fun!

3 Comments

Please don't do this, this is toxic to end users and dependencies alike, and makes it much harder for end users on older Perl's to use your code.

This is much more likely to make a vendor yell at you also.

This isn't Node or Java where you need to declare a newer version in order for a newer version to be used, end users can ( and will regularly ) do that on their own without you needing to declare updates.

You only have to state the minimum version that is expected to work, not the "latest".

The last thing you ever want to have happen is "I need this newer version of X to get feature Y", and then find >20+ other things you were using get updated, and break, because you hadn't planned on that upgrade yet.

Or worse still, you try to upgrade, and then in the process your upgrade causes requires updating a dependency to a version that requires a newer perl than you have, causing a deadlock where you can't actually upgrade, ... for no actual reason.

Upgrade deps only when necessary, not as a force of habit.

I'm not sure I understand the response.

My interpretation of what your module does in short is:

  • Get the current deps of your package
  • fetch data from metacpan to work out newest versions of those deps
  • set version requirements of your package to the returned values

The last of these is hostile, and should not be done.

If however, you performed a test in that last step, and that test indicated that a newer version of the dependency was required to function, then the last step is fine.

But you should never tell a user "Get a newer version of this" unless your own code will not work otherwise.

Leave a comment

About Steve Bertrand

user-pic Just Another Perl Hacker