DEV Community

David Cantrell
David Cantrell

Posted on

Monitoring dependencies on the CPAN

If you're anything like me you're a lazy bugger and prefer to write as little code as possible, instead relying on libraries that other people have written. This has several advantages: it's less work for you, the code has already been tested (you hope!) and debugged, someone else maintains it for you, and so on. The disadvantage is that those other people might change things, either accidentally or on purpose, and break your code. So if you're going to use other peoples' libraries it's a good idea to know what libraries you're actually using.

Easy to figure out, right? Just remember what you're using!

Oh if only it were that simple. You see, all those other people whose code you're using are just as lazy as you are, and they're all using third parties' libraries, and in turn those are using yet more libraries, and so on. As a learnèd sage once wrote:

Bigger fleas have littler fleas upon their backs to bite 'em,
And little fleas have lesser fleas, and so on, ad infinitum.

Many years ago I wrote a script 1 which shows the entire dependency tree for a module on the CPAN. Those trees grow surprisingly big surprisingly fast. For one of mine, it has 1 direct dependency, 8 second level dependencies, another 13 at the third level, and so it continues for a grand total of 41 2 dependencies.

Params::Validate::Dependencies::all_or_none_of (dist: D/DC/DCANTRELL/Params-Validate-Dependencies-all_or_none_of-1.01.tar.gz)
  Params::Validate::Dependencies (dist: D/DC/DCANTRELL/Params-Validate-Dependencies-1.40.tar.gz)
    Clone (dist: A/AT/ATOOMIC/Clone-0.45.tar.gz)
      B::COW (dist: A/AT/ATOOMIC/B-COW-0.004.tar.gz)
    Data::Domain (dist: D/DA/DAMI/Data-Domain-1.07.tar.gz)
      Date::Calc (dist: S/ST/STBEY/Date-Calc-6.4.tar.gz)
        Bit::Vector (dist: S/ST/STBEY/Bit-Vector-7.4.tar.gz)
          Carp::Clan (dist: E/ET/ETHER/Carp-Clan-6.08.tar.gz)
      List::MoreUtils (dist: R/RE/REHSACK/List-MoreUtils-0.428.tar.gz)
        Exporter::Tiny (dist: T/TO/TOBYINK/Exporter-Tiny-1.002002.tar.gz)
        List::MoreUtils::XS (dist: R/RE/REHSACK/List-MoreUtils-XS-0.428.tar.gz)
        Test::LeakTrace (dist: L/LE/LEEJO/Test-LeakTrace-0.16.tar.gz)
      Scalar::Does (dist: T/TO/TOBYINK/Scalar-Does-0.203.tar.gz)
        Test::NoWarnings (dist: A/AD/ADAMK/Test-NoWarnings-1.04.tar.gz)
        Test::Requires (dist: T/TO/TOKUHIROM/Test-Requires-0.11.tar.gz)
        Type::Tiny (dist: T/TO/TOBYINK/Type-Tiny-1.010006.tar.gz)
        URI (dist: O/OA/OALDERS/URI-1.76.tar.gz)
          Test::Needs (dist: H/HA/HAARG/Test-Needs-0.002006.tar.gz)
... and so on
Enter fullscreen mode Exit fullscreen mode

But even more important than knowing what's in your dependency tree is knowing when that tree changes, so that you know when you need to re-test your code to make sure no-one else broke it. Well, I've finally gone and created a tool for that, after having it on my to-do list for over a decade (did I mention above that I'm very lazy?).

It maintains a little database in ~/.cpandeps-diff of what a module's dependencies are, and every time you run it without any arguments it compares the dependencies it already knows about with what's on the CPAN, spitting out a side-by-side diff. Invoke it daily from your crontab and you'll get a daily email with any changes.

Start by telling it what modules you want to get reports about:

$ cpandeps-diff add CPAN::FindDependencies
$ cpandeps-diff add Sub::WrapPackages
$ cpandeps-diff add Number::Phone
Enter fullscreen mode Exit fullscreen mode

Each time it will go away to the CPAN, find what all the dependencies are, and store them in a file in that directory. You will also notice a cache directory, which is used to minimise traffic to the CPAN mirrors.

You can list which modules it knows about, and delete any that you are no longer interested in:

$ cpandeps-diff list

$ cpandeps-diff rm Sub::WrapPackages
Enter fullscreen mode Exit fullscreen mode

And you can get a report on an individual module:

$ cpandeps-diff report Number::Phone
Differences found in dependencies for Number::Phone:
|  3|E/ET/ETHER/Class-Method-Modifiers-2.13.tar.gz  |E/ET/ETHER/Class-Method-Modifiers-2.13.tar.gz  |
|  4|E/ET/ETHER/File-ShareDir-Install-0.13.tar.gz   |E/ET/ETHER/File-ShareDir-Install-0.13.tar.gz   |
|  5|E/ET/ETHER/Try-Tiny-0.30.tar.gz                |E/ET/ETHER/Try-Tiny-0.30.tar.gz                |
*  6|E/EX/EXODIST/Test-Exception-0.42.tar.gz        |E/EX/EXODIST/Test-Exception-0.43.tar.gz        *
|  7|H/HA/HAARG/Moo-2.004000.tar.gz                 |H/HA/HAARG/Moo-2.004000.tar.gz                 |
|  8|H/HA/HAARG/Role-Tiny-2.001004.tar.gz           |H/HA/HAARG/Role-Tiny-2.001004.tar.gz           |
Enter fullscreen mode Exit fullscreen mode

You can see in that report that a new version of Test-Exception has been released, and so I should make sure that the code which depends on it still works. If it turns out that that broke my code, that's annoying, but at least I found out about the problem before users started reporting bugs.

  1. I also created a website, originally based on largely the same code, which also shows test results for all dependencies and which has bit-rotted and become overloaded to the extent that it is no longer usable. Sorry about that. 

  2. or if you're using a really old version of perl, and so need upgraded versions of libraries distributed with the interpreter, you can more than double that. 

Top comments (4)

matthewpersico profile image
Matthew O. Persico

1) Not sure what those huge "L" blocks are in the code blocks.
2) Do you think the dependency list of this thing could be massaged and fed into

drhyde profile image
David Cantrell

1) Not sure what you mean by those huge L blocks.
2) That appears to be about inheritance, not dependencies.

matthewpersico profile image
Matthew O. Persico

1) The huge L blocks are gone - must've been some browser screwup.
2) Sure, but a graph is a graph. Updating cpandeps to spits out a graph might be interesting.

Thread Thread
drhyde profile image
David Cantrell

CPAN::FindDependencies does all the heavy lifting so feel free to use it to produce any format output you like :-) But beware that it won't produce a full graph of dependencies: a module such as Test::More might be a dependency of many different things, but will only appear once in the output.