]> git.donarmstrong.com Git - debhelper.git/blob - dh_python
r1844: merge python and gconf changes from python-support
[debhelper.git] / dh_python
1 #!/usr/bin/perl -w
2
3 =head1 NAME
4
5 dh_python - calculates python dependencies and adds postinst and prerm python scripts
6
7 =cut
8
9 use strict;
10 use File::Find;
11 use Debian::Debhelper::Dh_Lib;
12
13 =head1 SYNOPSIS
14
15 B<dh_python> [S<I<debhelper options>>] [B<-n>] [B<-V> I<version>] [S<I<module dirs ...>>]
16
17 =head1 DESCRIPTION
18
19 dh_python is a debhelper program that is responsible for generating the
20 ${python:Depends} substitutions and adding them to substvars files. It
21 will also add a postinst and a prerm script if required.
22
23 The program will look at python scripts and modules in your package, and
24 will use this information to generate a dependency on python, with the
25 current major version, or on pythonX.Y if your scripts or modules need a
26 specific python version. The dependency will be substituted into your
27 package's control file wherever you place the token "${python:Depends}".
28
29 If some modules need to be byte-compiled at install time, appropriate
30 postinst and prerm scripts will be generated. If already byte-compiled
31 modules are found, they are removed.
32
33 If you use this program, your package should build-depend on python.
34
35 =head1 OPTIONS
36
37 =over 4
38
39 =item I<module dirs>
40
41 If your package installs python modules in non-standard directories, you
42 can make dh_python check those directories by passing their names on the
43 command line. By default, it will check /usr/lib/$PACKAGE,
44 /usr/share/$PACKAGE, /usr/lib/games/$PACKAGE, /usr/share/games/$PACKAGE
45 and /usr/lib/python?.?/site-packages.
46
47 =item B<-V> I<version>
48
49 If the .py files your package ships are meant to be used by a specific
50 pythonX.Y version, you can use this option to specify the desired version,
51 such as 2.3.
52
53 =item B<-n>, B<--noscripts>
54
55 Do not modify postinst/postrm scripts.
56
57 =back
58
59 =head1 CONFORMS TO
60
61 Debian policy, version 3.5.7
62
63 Python policy, version 0.3.7
64
65 =cut
66
67 init();
68
69 my $python = 'python';
70
71 # The current python version
72 my $python_version = `$python -V 2>&1`;
73 if (! defined $python_version || $python_version eq "") {
74         error("Python is not installed, aborting. (Probably forgot to Build-Depend on python.)");
75 }
76 elsif ($python_version =~ m/^Python\s+(\d+)\.(\d+)(\.\d+)*/) {
77         $python_version = "$1.$2" ;
78 } else { 
79         error("Unable to parse python version out of \"$python_version\".");
80 }
81
82 # The next python version
83 my $python_nextversion = $python_version + 0.1;
84
85 my @python_allversions = ('1.5','2.1','2.2','2.3','2.4');
86 foreach (@python_allversions) {
87         s/^/python/;
88 }
89
90 # Check for -V
91 my $usepython = "python$python_version";
92 if($dh{V_FLAG_SET}) {
93         $usepython = $dh{V_FLAG};
94         $usepython =~ s/^/python/;
95         if (! grep { $_ eq $usepython } @python_allversions) {
96                 error("Unknown python version $dh{V_FLAG}");
97         }
98 }
99
100 # Cleaning the paths given on the command line
101 foreach (@ARGV) {
102         s#/$##;
103         s#^/##;
104 }
105
106 # dependency types
107 use constant PROGRAM   => 1;
108 use constant PY_MODULE => 2;
109 use constant PY_MODULE_NONSTANDARD => 4;
110 use constant SO_MODULE => 8;
111 use constant SO_MODULE_NONSTANDARD => 16;
112
113 foreach my $package (@{$dh{DOPACKAGES}}) {
114         my $tmp = tmpdir($package);
115
116         delsubstvar($package, "python:Depends");
117
118         my @dirs = ("usr/lib/$package", "usr/share/$package", "usr/lib/games/$package", "usr/share/games/$package", @ARGV );
119
120         my $dep_on_python = 0;
121         my $strong_dep = 0;
122         my $dep_on_py_support = 0;
123         my $look_for_pythonXY = 1;
124
125         # First, the case of python-foo and pythonX.Y-foo
126         if ($package =~ /^python-/) {
127                 $dep_on_python = 1;
128                 $strong_dep = 1;
129                 my $pack = $package;
130                 $pack =~ s/^python/python$python_version/;
131                 if (grep { "$_" eq "$pack" } getpackages()) {
132                         addsubstvar($package, "python:Depends", $pack);
133                 }
134         }
135         if ($package !~ /^python[0-9].[0-9]-/) {
136                 push @dirs, "usr/lib/$usepython/site-packages";
137                 $look_for_pythonXY = 0;
138         }
139
140         @dirs = grep -d, map "$tmp/$_", @dirs;
141
142         my $deps = 0;
143         my %verdeps = ();
144         foreach (@python_allversions) {
145                 $verdeps{$_} = 0;
146         }
147
148         # Find scripts
149         find sub {
150                 return unless -f and (-x or /\.py$/);
151                 local *F;
152                 return unless open F, $_;
153                 if (read F, local $_, 32 and m%^#!\s*/usr/bin/(env\s+)?(python(\d+\.\d+)?)\s%) {
154                         if ( "python" eq $2 ) {
155                                 $deps |= PROGRAM;
156                         } elsif(defined $verdeps{$2}) {
157                                 $verdeps{$2} |= PROGRAM;
158                         }
159                 }
160                 close F;
161         }, $tmp;
162
163         # Look for python modules
164         my $dirlist = "";
165         my $gen_dirlist = "";
166         my $moved_module = 0;
167         my $move_dir = "/usr/share/python-support/$package";
168         if (@dirs) {
169                 foreach my $curdir (@dirs) {
170                         my $has_module = 0;
171                         my $has_bin_module = 0;
172                         $curdir =~ s%^$tmp/%%;
173                         find sub {
174                                 return unless -f;
175                                 if (/\.py$/) {
176                                         $has_module = 1;
177                                         doit(("rm","-f",$_."c",$_."o"));
178                                 } elsif (/\.so$/) {
179                                         $has_bin_module = 1;
180                                 }
181                         }, "$tmp/$curdir" ;
182                         if ($has_module && $has_bin_module == 0) {
183                                 $dep_on_py_support = 1;
184                                 if ($curdir eq "usr/lib/$usepython/site-packages") {
185                                         doit(("mkdir","-p","$tmp$move_dir"));
186                                         complex_doit("mv \"$tmp/$curdir/\"* \"$tmp$move_dir\"/");
187                                         doit(("rmdir","-p","--ignore-fail-on-non-empty","$tmp/$curdir"));
188                                         $moved_module=1;
189                                 } else {
190                                         $gen_dirlist="$gen_dirlist /$curdir";
191                                 }
192                         } elsif ($has_module) {  # We have both kinds of modules
193                                 if ($dh{V_FLAG_SET}) {
194                                         $verdeps{$usepython} |= PY_MODULE_NONSTANDARD;
195                                 } else {
196                                         $deps |= PY_MODULE;
197                                 }
198                                 $dirlist="$dirlist /$curdir";
199                         }
200                         if ($has_bin_module) {
201                                 if ($dh{V_FLAG_SET}) {
202                                         $verdeps{$usepython} |= SO_MODULE_NONSTANDARD;
203                                 }
204                                 else {
205                                         $deps |= SO_MODULE;
206                                 }
207                         }
208                 }
209         }
210
211         # Dependencies on current python
212         $dep_on_python = 1 if $deps;
213         $strong_dep = 1 if($deps & SO_MODULE);
214
215         if ($dep_on_python) {
216                 addsubstvar($package, "python:Depends", $python, ">= $python_version");
217                 if ($strong_dep) {
218                         addsubstvar($package, "python:Depends", $python, "<< $python_nextversion");
219                 }
220         }
221
222         if ($dep_on_py_support) {
223                 addsubstvar($package, "python:Depends", "python-support");
224                 if ($gen_dirlist ne "") {
225                         autoscript($package, "postinst", "postinst-python-support", "s,#OPTIONS#,-b,;s,#DIRS#,$gen_dirlist,");
226                         autoscript($package, "prerm", "prerm-python-support", "s,#OPTIONS#,-b,;s,#DIRS#,$gen_dirlist,");
227                 }
228                 if ($moved_module) {
229                         autoscript($package, "postinst", "postinst-python-support", "s,#OPTIONS#,-i,;s,#DIRS#,$move_dir,");
230                         autoscript($package, "prerm", "prerm-python-support", "s,#OPTIONS#,-i,;s,#DIRS#,$move_dir,");
231                 }
232         }
233
234         my $need_prerm = 0;
235
236         # Look for specific pythonX.Y modules
237         foreach my $pyver (@python_allversions) {
238                 my $pydir="/usr/lib/$pyver/site-packages";
239                 if ($look_for_pythonXY) {
240                         if (grep -d,"$tmp$pydir") {
241                                 find sub {
242                                         return unless -f;
243                                         if (/\.py$/) {
244                                                 $verdeps{$pyver} |= PY_MODULE;
245                                                 doit(("rm","-f",$_."c",$_."o"));
246                                         }
247                                         $verdeps{$pyver} |= SO_MODULE if /\.so$/;
248                                 }, "$tmp$pydir";
249                         }
250                 }
251         
252                 # Go for the dependencies
253                 addsubstvar($package, "python:Depends", $pyver) if $verdeps{$pyver};
254
255                 # And now, the postinst and prerm stuff
256                 if ($pyver eq "$usepython") {
257                         if ($verdeps{$pyver} & PY_MODULE) {
258                                 $pydir = $pydir.$dirlist;
259                         } else {
260                                 $pydir = $dirlist;
261                         }
262                         $verdeps{$pyver} |= PY_MODULE if($deps & PY_MODULE);
263                 }
264                 if ($verdeps{$pyver} & (PY_MODULE|PY_MODULE_NONSTANDARD) && ! $dh{NOSCRIPTS}) {
265                         autoscript($package,"postinst","postinst-python","s%#PYVER#%$pyver%;s%#DIRLIST#%$pydir%");
266                         $need_prerm = 1;
267                 }
268         }
269         if ($need_prerm && ! $dh{NOSCRIPTS}) {
270                 autoscript($package,"prerm","prerm-python","s%#PACKAGE#%$package%");
271         }
272 }
273
274 =head1 SEE ALSO
275
276 L<debhelper(7)>
277
278 This program is a part of debhelper.
279
280 =head1 AUTHOR
281
282 Josselin Mouette <joss@debian.org>
283
284 most ideas stolen from Brendan O'Dea <bod@debian.org>
285
286 =cut