RFC Module::Build::CleanInstall
Edit: Module::Build::CleanInstall has been released!
Following the recent work (chronicled here) by Yanick Champoux and this StackOverflow question, I got it into my mind to try to write a Module::Build subclass which first removes all the files previously installed by a module before installing the new version. In those posts, this is motivated by File::ShareDir
concerns, but this problem is more general than that.
If your new version of a module does not come with some file that a previous version did, installing the new version will not remove that file. Most of the time this is ok, but every now and again you need to know that those files don’t exist. That’s usually when you see warnings in the POD saying, “be sure to remove all previous installations …” or “only install on a fresh copy of Perl”. The author knows that a problem is possible, but the user has to fix it. Sounds bad.
What if you could just switch your build tool from Module::Build (or EU::MM) to Module::Build::CleanInstall
and let that take care of it for you?
Normally once I mock up an example, I release it to CPAN and see how it goes, but this time, I thought I might solicit comments first, since perhaps there are real world considerations I haven’t thought of. Please let me know any thoughts on this idea and the proposed implementation in the comments below.
Hi
Sounds like a great idea, actually.
Just 1 question: Does does the code know there are files missing from the current version which were present in the previous version?
Cheers Ron
Nope, it simply removes everything in the previous version’s packlist before install the new version. Its for this reason that I don’t think that you would switch from Module::Build to M::B::CleanInstall until you had reason to believe that you should. Not that there would be any fear in doing so, but it would involve extra (and unnecessary) disk i/o on installing.
Looks great. If the packlist is not there, no foul done, and if it is, it neatly clean and vacuum the place.
I can’t think of a way how this could have adverse consequences, but you are right in requesting comments before unleashing the beast, juuuust in case. I’d have done the same. :-)
But yeah, huge +1 from here!
prepan.org is a good place to get feedback before releasing to CPAN.
Ok, its out there!
This looks to me like what you really want is the —uninst argument to Module::Build (it’s a documented feature of Module::Build. Actually, you can simply do
And be done with it (not tested, but if it doesn’t work that’s a bug that should be fixed).
Wow, in all the times I have looked at M::B’s documentation (and source) I have never seen that feature. I just checked and it isn’t documented in M::B::API which is where all the other arguments to
new
are found (and where I typically go first for doc). I know that the question of removing previous files comes up regularly, so perhaps this should be featured more prominently.I haven’t yet looked at the source to see how the uninst option works, perhaps there is still value to both.
Looks like it’s mentioned in Module::Build::Cookbook.
Module::Build::Cookbook
documents command option--uninst 1
. It also appears thatModule::Build->new( uninst => 1, ... )
has the effect of defaulting the command option to1
, though I can’t find where this is documented.However, I can’t make it actually remove anything. That is, if the installed package
Foo-pkg
provides modulesFoo
andFoo::Bar
, and you install a new packageFoo-pkg
that only providesFoo
, it does not appear to me thatFoo::Bar
goes away even withuninst => 1
.The same seems to be true of ExtUtils::MakeMaker, though that’s more complicated since you can’t get that behavior by calling
WriteMakeFile( UNINST => 1, ... )
.I would love to be proven wrong on this. I have a package that will shortly loose a module, and I would love to be able to get rid of the surplus file using standard CPAN toolchain modules — but it may not be possible.
But given what I think I know at the moment, it looks to me like
Module::Build::CleanInstall
still has value.I haven’t had too much time to dig into it, but here’s the deal: the
uninst
option is basically an option toExtUtils::Install::install
which handles making packlists and everything during the installation process. M::B::CleanInstall relies onExtUtils::Install::uninstall
which is (obviously) from the same package, but is a different function. I would have thought thatinstall
with the uninstall option would internally calluninstall
, and thus the value isn’t there. However now with your report, you or I should dive into the code from ExtUtils::Install:: and see what’s going on. I would quite interested.If this doesn’t work it’s a bug in ExtUtils::Install and should be fixed there.
Ok, so I have looked around the source, and it is as I suspected. Even if
uninst
is set, it doesn’t remove files as my module does. Its task is to take a file that is being installed and search for any similar one in @INC. This will do nothing in the case I present in the original post. My module on the other hand does not search in @INC but rather removes all the files from the previous version’s packlist.I might consider trying to have M::B::CleanInstall set
uninst => 1
, but I’m not sure that’s necessary.