Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Update dependants if installed (was: Update these modules if installed?)

by perlancar (Friar)
on Mar 08, 2020 at 02:14 UTC ( #11113958=perlquestion: print w/replies, xml ) Need Help??

perlancar has asked for the wisdom of the Perl Monks concerning the following question:

In a Perl distribution, what would be the recommended way to specify a "dependency" type that says: update these modules to at least these versions, if you have them installed?

In my case, I'm releasing Log-ger 0.033 which will break *some* plugins. These plugins currently do not specify a dependency to Log::ger, because they do not actually require() or use() Log::ger, but instead are used together by users in the user's code. However, the plugins do "depend" on the Log::ger API and will break if the Log::ger API change in some non-backward-compatible way. Ideally I'm thinking, these plugins should've declared something like (phase=x_api, rel=requires) dependency to Log::ger; and CPAN clients have a plugin to recognize this dependency and performs update when necessary. Or is there another way?

EDIT: After another read of my own post, I realize that this is just a case of "updating dependants", which I think generally should be the user's choice, because automatically updating dependants could start a chain reaction of breakage.

  • Comment on Update dependants if installed (was: Update these modules if installed?)

Replies are listed 'Best First'.
Re: Update these modules if installed?
by syphilis (Bishop) on Mar 08, 2020 at 03:14 UTC
    In a Perl distribution, what would be the recommended way to specify a "dependency" type that says: update these modules to at least these versions, if you have them installed?

    I would do something like (untested):

    In the Makefile.PL, list all dependencies along with their minimum required versions:
    ... my %min_version = (Some/Place/Foo.pm => 0.06, # need at least version +0.06 of Some::Place::Foo Other/Spot/Bar.pm => 1.35, # need at least version +1.35 of Other::Spot::Bar Baz.pm => 2.72, # need at least version +2.72 of Baz ); my @prereqs; for(keys(%min_version)) { eval {require $_}; # Ignore modules that don't load. unless($@){ my $m = $_; $m =~ s/\//::/g; $m =~ s/\.pm$//; my $v = $min_version{$_}; push @prereqs($m, $v); } } my %h = @prereqs; ....
    And then, in WriteMakefile() section of the Makefile.PL, I would specify:
    ... 'PREREQ_PM' => \%h, ...
    Cheers,
    Rob

      Thanks, that's what I first thought too (dynamically generating the dependencies). However, in my case, Log::ger wants to update its *dependants* and I'm afraid adding them to the list of prereqs will trigger a circular dependency. So installing dependants will need to be performed after the installation of itself.

        adding them to the list of prereqs will trigger a circular dependency

        It's only a problem if those prereqs themselves specify a version of Log::ger that's newer than the Log::ger that's currently installed. (And there must be a Log::ger that's "currently installed", or the "list of prereqs" would be empty.)
        So, I guess that's the issue.

        IIUC, your question could therefore be generalized as:
        "How do I, as maintainer of both the Foo and Bar modules, ensure that Bar, which is dependant upon Foo, is automatically updated whenever Foo is updated ?"
        Maybe just bundle Foo and Bar into the same distro ? (I think that would be the "approved" method, though I wouldn't like to assert that it's always desirable.)

        Other than that, I can't really think of anything that hasn't already been mentioned.

        Cheers,
        Rob
Re: Update these modules if installed?
by LanX (Cardinal) on Mar 08, 2020 at 02:21 UTC
    > because they do not actually require() or use() Log::ger, but instead are used together by users in the user's code. However, the plugins do "depend" on the Log::ger API

    How is it possible to depend on the API of a module one doesn't require ?

    IMHO if you need another modules API, then you are calling it's subs or methods, hence you need to import them.

    Sorry, this really smells like bad design.

    edit

    anyway, IIRC you are able to list dependencies to other modules and versions as JSON or YAML in a distribution without actually importing them.

    update

    see CPAN::Meta

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

      I am talking about API in a more general sense instead of the more restricted sense of calling a module's functions/methods or variables. In the Log::ger case, a plugin returns a hash of hooks with names that are agreed upon. This is not enforced "mechanically", which can be a bad design choice in itself but I am choosing minimalism over stricture.

      Anyway, making the plugin depends explicitly to Log::ger does not solve my problem. If Log::ger changes in a backward-incompatible way, I *will* break installed plugins unless clients choose to update the plugins (the dependants).

        Why not just introduce some code in your distribution that can catch the plugins doing things the old, broken way, and gracefully throw a notice to the user and exit, with the notice advising them to upgrade the broken plugin (caller() could potentially be used to get the plugin name)?

        Not ideal, but significantly better than forcing an upgrade of user installed distributions.

        Thanks for the clarification, tho that's a bit over my head.

        Hope Syphilis approach helps. :)

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

Re: Update dependants if installed (was: Update these modules if installed?)
by tobyink (Canon) on Mar 09, 2020 at 08:48 UTC

    There's a "conflicts" key available in META.json:

    ... "runtime": { "requires": { ... }, "conflicts": { "Log::ger::Some::Plugin": "< 0.5", "Log::ger::Other::Plugin": "< 0.3" } }

    However, as far as I'm aware, CPAN clients don't actually look at this information and use it to upgrade stuff. Your Makefile.PL (or a script in your test suite) could look at it though, and perhaps spit out some very visible warnings.

      Ah yes, perhaps CPAN clients should upgrade on conflicts of "Some::Module < 0.123", although this would still cause a circular dependency failure in the case of upgrading dependants.

      I'm afraid a warn() in Makefile.PL or diag() in a test script will not be seen by many cpanminus users unless they use the verbose (-v) option. And a die() will be annoying.

        Yeah, the lack of feedback to cpanm users is an annoyance.

        Just a random thought; not great, but could be helpful. At configure-time, you could modify your pod to add an "INSTALLATION NOTES" section with text like: "This software was installed on $date at $time. At the time of installation, the following packages were already installed but now need upgrading".

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://11113958]
Approved by LanX
Front-paged by haukex
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (3)
As of 2020-07-10 04:02 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?