-=| 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