[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Distribution installer that defaults to Debian?



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


Reply to: