-=| Joel Roth, Wed, Dec 22, 2010 at 01:00:09PM -1000 |=-
> On Mon, Dec 20, 2010 at 02:13:07PM +0200, Gabor Szabo wrote:
> > It would be nice to see this on CPAN to encourage distributions to
> > implement the same.
>
> Okay, well, first what about having a look at the script
> below? Does it do what you'd want?
Commented below.
> Then, what about a name?
>
> CPAN::NativePackageInstaller::Debian
>
> CPAN::Installer::Debian
>
> Debian::CPAN::HybridInstaller
>
> Would there be any benefit to prefixing App:: ?
Hm, whould that be extended to support other distributions than
Debian? If yes, having the generic code (including the detection of
the distribution-specific module to load) in a generic module, and
distribution specific code in corresponding module may be wanted.
CPAN::HybridInstaller - generic code
CPAN::HybridInstaller::Debian, CPAN::HybridInstaller::Fedora etc.
> The script might be named 'dcpan', easy to type and remember
>
> > I also wonder if it could be integrated into CPAN.pm (and friends)
> > itself so if I type
> >
> > cpan Module::Name it will install dependencies using apt-get - if
> > possible and using cpan (with local::lib)
> > otherwise.
>
> I think this would work at the top level, where
> the user is not constraining the version number.
"Plugging" this recursively in cpan or another tool would be the
cherry of the icecream. Top-level is OK, but if you install something
with lots of dependencies the gain will not be that big.
> The harder problem is the dependency case you mentioned.
>
> > BTW what happens if a secondary dependency is available as a
> > .deb package ? I mean if I am installing package X which
> > depends on Y which in turn depends on W and only W is in
> > .deb X and Y are not. Will your script notice this situation
> > and install W using apt-get ?
>
> Say Y requires W (>=0.5), but the corresponding Debian
> libw-perl is only 0.4.
>
> It seems we can't reliably extract the upstream version from the
> Debian package metadata. An enhanced CPAN client might
> work around this limitation by:
>
> - installing the Debian package for W
> - seeing if Y's dependency is met
> - falling back to installing W from CPAN.
It seems to me that this would work reliably, at the expense of the
possibility of unnecessarily installing packaged modules.
I was thinking about the version problem, and I think it is possible
to reach a sufficiently good approach:
1) strip epoch (s/^\d+://)
2) strip revision (s/-[^-]$//)
3) strip repackaging suffix (s/[+.](?:dfsg|ds)\.?\d*$)
4) what is left should be suitable for feeding version.pm and then
comparing with the wanted version. If the version of the
package was mangled, this is most likely 1.23 -> 1.2300
extension, which is irrelevant to version.pm (AIUI).
or
5) compare what is left with the wanted version using *dpkg*
version comparison functions (available somewhere in the Dpkg::
namespace). If the version was mangled, the debian-extracted
version should compare greater than the wanted version, which
would work for the purpose of deciding "is the package
sufficiently new".
Finally, there is a caveat with @INC, that I am not sure how to
address. Thing is, 'cpan' installs packages in /usr/local, and
Debian's perl has that path before /usr in @INC. I guess local::lib
does something similar. The problem is that once you install a module
there, it will take precedencde and will always be used regardles of
the fact that there may be a Debian package installed which has
a greater version. So once you install a module not using the package
manager, you have to either upgrade it when needed or uninstall it and
use the packaged one.
> --- script: dcpan ----
>
> #!/usr/bin/perl
> use Debian::AptContents;
> use Module::Load::Conditional 'check_install';
> use YAML::Tiny;
> use Getopt::Std;
> use Modern::Perl;
> no warnings 'uninitialized';
>
> my $c = Debian::AptContents->new( { homedir => '/tmp/.dh-make-perl' } );
>
> # flags:
> # -i - install
>
> our $opt_i;
> getopt('i');
>
> # input should be perl module name, i.e. DBIx::Class:Schema
>
> my $want = shift;
>
> say qq(\nSearching for "$want"\n);
>
> my $href = check_install(module => $want);
>
> if ( defined $href )
> {
> say qq(Module $want is already installed.);
> my $y = YAML::Tiny->new;
> $y->[0] = $href;
> my $output = $y->write_string();
> $output =~ s/^---.//s;
> say join "\n ",'',split "\n",$output;
> }
Should the script exit here if the module is already available?
> my( @apt_file_pkgs, @find_file_pkgs );
>
> unless($want =~ /::/){
>
> @apt_file_pkgs = split "\n",qx(apt-file -l find $want);
Perhaps you mean 'search' instead of 'find' here. And possibly
$want.pm instead of $want
> say_results("apt-file",@apt_file_pkgs);
This would give false positives, for example if you give it 'Find' it
would return any package containing a file named 'Find[.pm]', not
necessarily providing the possibility to "use Find;"
> @find_file_pkgs = $c->find_file_packages($want);
> say_results("file name",@find_file_pkgs);
>
> # hmm, no output at all for this
> }
>
> my $find_perl_pkg = $c->find_perl_module_package($want);
> say_results("distribution name",$find_perl_pkg);
>
> # which to install
>
> my @debian_available = (
> @find_file_pkgs,
> @apt_file_pkgs,
> );
>
> my $debian_pkg = $find_perl_pkg || shift @debian_available;
>
> say "Installation candidate for $want ",
> ($opt_i ? "is " : "would be "),
> $debian_pkg ? qq("$debian_pkg") : "CPAN";
>
> # stop here unless instructed to install (-i option)
>
> say("\nUse -i flag to install."), exit unless $opt_i;
>
> if ($debian_pkg)
> {
> system("sudo apt-get install $debian_pkg");
> }
> else
> {
> # choose installer, prefering cpanm to cpan
>
> my $cpan_installer = qx(which cpanm) || qx(which cpan);
>
> say("No installer found, neither 'cpan' nor 'cpanm'. Aborting."),
> exit unless $cpan_installer;
>
> system("$cpan_installer $want");
> }
>
> sub say_results {
> my ($method, @results) = @_;
> $results[0] or return;
> say "Search by $method found packages:\n", join "\n ", '',@results;
> say;
> }
> __END__
Attachment:
signature.asc
Description: Digital signature