#!/usr/bin/perl -w =head1 NAME dh_pysupport - use the python-support framework to handle Python modules =cut use strict; use File::Find; use Debian::Debhelper::Dh_Lib; =head1 SYNOPSIS B [S>] [-V I] [-n] [S>] =head1 DESCRIPTION dh_pysupport is a debhelper program that will scan your package, detect public modules in I and generate appropriate postinst/prerm scripts to byte-compile modules installed there for all available python versions. It will also look for private Python modules and will byte-compile them with the current Python version. You may have to list the directories containing private Python modules. If a file named I exists, it is installed in I. =head1 OPTIONS =over 4 =item I If your package installs private python modules in non-standard directories, you can make dh_pysupport check those directories by passing their names on the command line. By default, it will check /usr/lib/$PACKAGE, /usr/share/$PACKAGE, /usr/lib/games/$PACKAGE and /usr/share/games/$PACKAGE =item B<-n>, B<--noscripts> Do not modify postinst/postrm scripts. =item B<-d> Force generation of dependency information. In normal operation, dh_pysupport only generates complete dependency information when no I file is found. With this option, it will be generated regardless. =item B<-V> I Force private modules to be bytecompiled with the specific I python version, regardless of the default python version on the system. =back =head1 CONFORMS TO Python policy as of 2006-06-10 =cut init(); sub next_minor_version { my $version = shift; # Handles 2.10 -> 2.11 gracefully my @items = split(/\./, $version); $items[1] += 1; $version = join(".", @items); return $version; } # The current default python version my $default=`pyversions -dv`; chomp $default; # All supported versions my $allversions_string=`pyversions -sv`; chomp $allversions_string; my @allversions=split " ", $allversions_string; # Use a specific version for private modules (doesn't affect public modules) my $useversion; if($dh{V_FLAG_SET}) { $useversion = $dh{V_FLAG}; if (! grep { $_ eq $useversion } @allversions) { error("Unknown python version $useversion"); } } # Generate dependencies if dh_python's debian/pycompat file isn't here my $do_deps=1; if (-f "debian/pycompat" && ! $dh{D_FLAG}) { $do_deps=0; } foreach my $package (@{$dh{DOPACKAGES}}) { my $tmp = tmpdir($package); my $have_pydep=0; # This variable tells whether we have added some dependency # on python one way or another. # 1) Handle public python modules # Move them to the python-support directories doit (("pysupport-movemodules",$tmp)); # Then look for what the script found foreach my $ps_dir (glob("$tmp/usr/share/python-support/*")) { if (-d $ps_dir) { my $verfile = "debian/pyversions"; if (-f $verfile) { # TODO: debian/package.pyversions ? doit("install","-p","-m644",$verfile,"$ps_dir/.version"); } my $ext_dir=$ps_dir; $ext_dir =~ s,/usr/share/,/usr/lib/,; my $supported; if (-d $ext_dir) { if (-f "$ps_dir/.version") { # Just ignore the .version file when there are extensions. # The extensions dictate which versions to handle. doit(("rm","-f","$ps_dir/.version")); } my @provides; foreach my $pydir (glob("$ext_dir/python*")) { if (-d $pydir && $pydir =~ m/python(\d+).(\d+)/) { push @provides, "$1.$2"; } } my $a=join ",",@provides; $supported=`echo $a | pysupport-parseversions --minmax`; } elsif (! -f "$ps_dir/.version") { my $doko_versions=`pysupport-parseversions --raw --pycentral debian/control`; chomp $doko_versions; if ($doko_versions !~ /not found/) { print "Compatibility mode: using detected XS-Python-Version.\n"; complex_doit("echo $doko_versions > $ps_dir/.version"); } } if (-f "$ps_dir/.version") { $supported=`pysupport-parseversions --minmax $ps_dir/.version`; } if ($do_deps && defined $supported) { # Generate the provides field my @ar=split "\n",$supported; my @provides=split " ",$ar[0]; if ($package =~ /^python-/) { foreach my $pyversion (@provides) { my $virtual = $package; $virtual =~ s/^python-/python$pyversion-/; addsubstvar($package, "python:Provides", $virtual); } } my @minmax=split " ",$ar[1]; my $minversion=$minmax[0]; if ( grep { $_ eq $default } @provides ) { # The default version is in the supported versions if ($minversion ne "None") { addsubstvar($package, "python:Depends", "python (>= $minversion)"); } } elsif ($minversion ne "None") { # The default version is less than all supported versions addsubstvar($package, "python:Depends", "python (>= $minversion) | python$minversion"); } else { error("The default python version is greater than all supported versions"); } my $maxversion=$minmax[1]; if ($maxversion ne "None") { $maxversion = next_minor_version($maxversion); addsubstvar($package, "python:Depends", "python (<< $maxversion)"); } $have_pydep=1; } $ps_dir =~ s/^$tmp//; if (! $dh{NOSCRIPTS}) { autoscript($package, "postinst", "postinst-python-support", "s,#OPTIONS#,-i,;s,#DIRS#,$ps_dir,"); autoscript($package, "prerm", "prerm-python-support", "s,#OPTIONS#,-i,;s,#DIRS#,$ps_dir,"); } } } # 2) Look for private python modules my @dirs = ("/usr/lib/$package", "/usr/share/$package", "/usr/lib/games/$package", "/usr/share/games/$package", @ARGV ); @dirs = grep -d, map "$tmp$_", @dirs; my @dirlist; my $have_pyversion=0; my $need_pydep=0; my %need_verdep = (); foreach (@allversions) { $need_verdep{$_} = 0; } if (@dirs) { foreach my $curdir (@dirs) { my $has_module = 0; find sub { return unless -f; if (/.py$/) { $has_module=1; doit(("rm","-f",$_."c",$_."o")); } }, $curdir ; if ( $has_module and not grep { $_ eq "$curdir" } @dirlist ) { # Create .pyversion to tell update-python-modules for which # version to compile if ( $useversion ) { open(VERFILE, "> $curdir/.pyversion") || error("Can't create $curdir/.pyversion: $!"); print VERFILE "$useversion\n"; close(VERFILE); $have_pyversion=1; $need_verdep{$useversion}=1; } else { $need_pydep=1; } $curdir =~ s%^$tmp%%; push @dirlist, "$curdir"; } } } if (@dirlist) { # We have private python modules # Use python-support to ensure that they are always # byte-compiled for the current version mkdir("$tmp/usr/share/python-support"); open(DIRLIST, "> $tmp/usr/share/python-support/$package.dirs") || error("Can't create $tmp/usr/share/python-support/$package.dirs: $!"); print DIRLIST map "$_\n", @dirlist; close(DIRLIST); autoscript($package, "postinst", "postinst-python-support", "s,#OPTIONS#,-b,;s,#DIRS#,$package.dirs,"); autoscript($package, "prerm", "prerm-python-support", "s,#OPTIONS#,-b,;s,#DIRS#,$package.dirs,"); } # 3) Add python-support dependency depending on what we found if (-d "$tmp/usr/share/python-support") { if ( $have_pyversion ) { # .pyversion introduced in 0.4 addsubstvar($package, "python:Depends", "python-support (>= 0.4) "); } elsif (-d "$tmp/usr/lib/python-support") { # /usr/lib split introduced in 0.3 addsubstvar($package, "python:Depends", "python-support (>= 0.3.4) "); } else { # stateless stuff introduced in 0.2 addsubstvar($package, "python:Depends", "python-support (>= 0.2) "); } } # 4) Look for python scripts if ($do_deps) { find sub { return unless -f and -x; local *F; return unless open F, $_; if (read F, local $_, 32 and m%^#!\s*/usr/bin/(env\s+)?(python(\d+\.\d+)?)\s%) { if ( "python" eq $2 ) { $need_pydep=1; } elsif (defined $need_verdep{$3}) { $need_verdep{$3}=1; } } close F; }, $tmp; } # 5) Generate remaining dependencies if ($do_deps) { foreach (@allversions) { if ($need_verdep{$_}) { addsubstvar($package, "python:Depends", "python$_"); } } if ($need_pydep and not $have_pydep and -f "debian/pyversions") { my $supported=`pysupport-parseversions --minmax debian/pyversions`; my @ar=split "\n",$supported; my @minmax=split " ",$ar[1]; my $minversion=$minmax[0]; if ($minversion ne "None") { addsubstvar($package, "python:Depends", "python (>= $minversion)"); $have_pydep=1; } my $maxversion=$minmax[1]; if ($maxversion ne "None") { $maxversion = next_minor_version($maxversion); addsubstvar($package, "python:Depends", "python (<< $maxversion)"); $have_pydep=1; } } if ($need_pydep and not $have_pydep and not -d "$tmp/usr/share/python-support") { # Nothing else depends on python but we need it addsubstvar($package, "python:Depends", "python"); } } } =head1 SEE ALSO L This program is a part of python-support but is made to work with debhelper. =head1 AUTHORS Josselin Mouette , Raphael Hertzog =cut