Hi! Please consider following me on twitter: @hanekomu.
2009年10月05日
Repeatedly installing Task::* distributions
First there were Bundle::* distributions to install several
dependencies at once without the actual bundle distribution doing anything,
but this required magic in the toolchain. A newer concept is that of a
Task::* distribution, as described in Task.
Task modules are just normal Perl modules; they don't require toolchain
magic. When the dependencies listed in Makefile.PL have been
installed, the actual Task module, for example Task::Catalyst, will be installed as well.
This is a problem because if the task's dependencies are being updated,
the task module needs to be updated as well. For example, DBD::SQLite is a dependency of
Task::Catalyst. If there is a new version of
DBD::SQLite, just running
install Task::Catalyst in the CPAN shell won't have any
effect, because the CPAN shell will see that the latest version of
Task::Catalyst is already installed. Of course you can force
with force install Task::Catalyst, but even if that would
work, it would be ugly because I don't want to install dependencies that
fail their tests.
One solution is to prevent the task module itself to be installed. That
way, every time you rerun install Task::Foo in the CPAN
shell, it will see that the task module isn't installed and try to install
it again, with all the desired dependency checking.
How do we prevent the module from being installed? Put these lines in
your Makefile.PL — I always use Module::Install, but I think this should work for all
MakeMaker-based files:
exit 0 if $ENV{AUTOMATED_TESTING}; sub MY::install { "install ::\n" }
First, we don't need to waste the time of CPAN testers by having them
install all the dependencies for a task module that doesn't really do
anything anyway. Second, and more importantly, we override the
install :: target that is generated for the
Makefile to effectively be a no-op.
I have demonstrated this technique in Task::BeLike::hanekomu, a somewhat pointless distribution
that serves mainly as proof-of-concept, and as a way to install my
favourite modules onto a new perl installation. If you don't mind the
dependencies, then go ahead and repeatedly run
install Task::BeLike::hanekomu in the CPAN shell; the
task module itself should never be installed and it should recheck the
dependencies every time.
I think this would be a good thing to put in existing task distributions such as Task::Kensho and Task::Catalyst.
posted at: 12:27 | path: /dev | permalink | 6 comments | 1 trackback
hanekomu wrote at 2009-10-06 10:49:
Yanick: Well, if you're happy with the installation, don't install it again. :) But if you want to upgrade the tasks's dependencies to their latest versions - not an unreasonable wish I believe - then previously you had no choice short of deleting the Task::* module or other less subtle methods.
I mean, when you write a task you simply say "I want those modules to be installed, and at least these versions". It doesn't mean that you don't intend the user to keep up-to-date with the dependencies.
Matt S Trout wrote at 2009-10-06 18:09:
Actually, the key problem is that the Task module needs to be updated regularly. Automate that and the problem goes away.
Hacking around people not updating Tasks by rendering the module uninstallable is just gross.
-- mst, out
Yanick wrote at 2009-10-06 18:33:
I think we are thinking the same thing, but have different conceptions of how the dependencies are going to be treated. :-)
Let's walk through an example, and hope it makes things clearer.
Let's say that we have Task::BeLike::Me, which has Foo:Bar as a dependency.
If we install Task::BeLike::Me for a first time, it'll follow its dependencies and install Foo::Bar as well. Yay.
Now, if I understand correctly, you'd like the Task to subsequently install a new version of Foo::Bar if it appears on CPAN. One problem, that you identify correctly, is that doing 'cpan Task::BeLike::Me' will do nothing because T::BL::M itself does not have a new version.
What I'm wondering is, even if Task::BeLike::Me wasn't installed, or if we install it by force, we would still not pull the new version of Foo::Bar, because the dependency check is only about having Foo::Bar, which we do, and not having its latest version. Unless Module::Install behaves differently than Module::Build in that regard?
So, as far as I can see, the only ways to cause the update to the latest version is either to do it manually ('cpan Foo::Bar'), or to update the Makefile.pl of T::BL::M so that it requires the new version of Foo::Bar we desire, in which case we created a new version of T::BL::M and CPAN will willingly upgrade when we'll do 'cpan Task::BeLike::Me'.
Does my reasoning make some kind of sense? :-)
Tatsuhiko Miyagawa wrote at 2009-10-06 23:07:
I think Yanick is right, unless you have some magic in Makefile.PL to always *explicitly* require the newest version by checking CPAN.pm index or whatever. Having "requires 'Foo';" in Makefile.PL doesn't automatically pull the newest version.
Yanick wrote at 2009-10-07 00:50:
Actually, all this gave me an evil, evil idea. I'll try to have a blog entry about it for tomorrow. Stay tuned! :-)
Pythian Group Blog mentioned this post in "Perl Module Dependencies: how to require the latest, and nothing less"
Recently, hanekomu was contemplating how to make subsequent installs of a Task::BeLike module upgrade its dependencies to their latest version. This gave me ideas… ...
eq="">.?>Recently, hanekomu was contemplating how to make subsequent installs of a Task::BeLike module upgrade its dependencies to their latest version. This gave me ideas… ...
ne="">:?>Recently, hanekomu was contemplating how to make subsequent installs of a Task::BeLike module upgrade its dependencies to their latest version. This gave me ideas… ...
Comments are closed for this story.
Trackbacks are closed for this story.
Yanick wrote at 2009-10-06 05:25: