summaryrefslogtreecommitdiff
path: root/dh_python
blob: 81da6da5e6e215a35ee28e555cc1bd85c2b86653 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#!/usr/bin/perl -w

=head1 NAME

dh_python - calculates python dependencies and adds postinst and prerm python scripts

=cut

use strict;
use File::Find;
use Debian::Debhelper::Dh_Lib;

=head1 SYNOPSIS

B<dh_python> [S<I<debhelper options>>] [B<-n>] [S<I<module dirs ...>>]

=head1 DESCRIPTION

dh_python is a debhelper program that is responsible for generating the
${python:Depends} substitutions and adding them to substvars files. It
will also add a postinst and a prerm script if required.

The program will look at python scripts and modules in your package, and
will use this information to generate a dependency on python, with the
current major version, or on pythonX.Y if your scripts or modules need a
specific python version. The dependency will be substituted into your
package's control file wherever you place the token "${python:Depends}".

If some modules need to be byte-compiled at install time, appropriate
postinst and prerm scripts will be generated.

If you use this program, your package should build-depend on python.

=head1 OPTIONS

=over 4

=item I<module dirs>

If your package installs python modules in non-standard directories, you
can make dh_python check those directories by passing their names on the
command line. By default, it will check /usr/lib/site-python,
/usr/lib/$PACKAGE, /usr/share/$PACKAGE, /usr/lib/games/$PACKAGE,
/usr/share/games/$PACKAGE and /usr/lib/python?.?/site-packages.

=item B<-n>, B<--noscripts>

Do not modify postinst/postrm scripts.

=back

=head1 CONFORMS TO

Debian policy, version 3.5.7

Python policy, version 0.3.7

=cut

init();

my $python = 'python';

# The current python major version
my $python_major;
my $python_version = `$python -V 2>&1`;
if ("$python_version" eq "") {
	error("Python is not installed, aborting. (Probably forgot to Build-Depend on python.)");
}
elsif ($python_version =~ m/^Python\s+(\d+)\.(\d+)\.\d+/) {
	$python_version = "$1.$2" ;
	$python_major = $1 ;
} else { 
	error("Unable to parse python version out of \"$python_version\".");
}

# The next python version
my $python_nextversion = $python_version + 0.1;
my $python_nextmajor = $python_major + 1;

my @python_allversions = ('1.5','2.1','2.2','2.3');
foreach (@python_allversions) {
	s/^/python/;
}

# Cleaning the paths given on the command line
foreach (@ARGV) {
	s#/$##;
	s#^/##;
}

# dependency types
use constant PROGRAM   => 1;
use constant PY_MODULE => 2;

foreach my $package (@{$dh{DOPACKAGES}}) {
	my $tmp = tmpdir($package);

	delsubstvar($package, "python:Depends");

	# Check for current python dependencies
	my @dirs = ("usr/lib/site-python", "usr/lib/$package", "usr/share/$package", "usr/lib/games/$package", "usr/share/games/$package", @ARGV );
	@dirs = grep -d, map "$tmp/$_", @dirs;

	my $deps = 0;
	my %verdeps = ();
	foreach (@python_allversions) {
		$verdeps{$_} = 0;
	}

	# Find scripts
	find sub {
		return unless -f and (-x or /\.py$/);
		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 ) {
				$deps |= PROGRAM;
			} elsif(defined $verdeps{$2}) {
				$verdeps{$2} |= PROGRAM;
			}
		}
		close F;
	}, $tmp;

	# Look for python modules
	my $dirlist="";
	if (@dirs) {
		foreach my $curdir (@dirs) {
			my $has_module = 0;
			$curdir =~ s%^$tmp/%%;
			find sub {
				return unless -f;
				$has_module = 1 if /\.py$/;
			}, "$tmp/$curdir" ;
			if ($has_module) {
				$deps |= PY_MODULE;
				$dirlist="$dirlist /$curdir";
			}
		}
	}

	# Dependencies on current python
	my $dep_on_python = 0;
	my $strong_dep = 0;
	$dep_on_python = 1 if $deps;
	$strong_dep = 1 if($deps & PY_MODULE);
	if ($package =~ /^python-/) {
		my $pack = $package;
		$pack =~ s/^python/python$python_version/;
		if (grep { "$_" eq "$pack" } GetPackages()) {
			addsubstvar($package, "python:Depends", $pack);
			$dep_on_python = 1;
			$strong_dep = 1;
		}
	}
	if ($dep_on_python) {
		addsubstvar($package, "python:Depends", $python, ">= $python_version");
		if ($strong_dep) {
			addsubstvar($package, "python:Depends", $python, "<< $python_nextversion");
		} else {
			addsubstvar($package, "python:Depends", $python, "<< $python_nextmajor");
		}
	}

	my $need_prerm = 0;

	# Look for specific pythonX.Y modules
	foreach my $pyver (@python_allversions) {
		my $pydir="/usr/lib/$pyver/site-packages";
		if (grep -d,"$tmp$pydir") {
			find sub {
				return unless -f;
				$verdeps{$pyver} |= PY_MODULE if /\.py$/;
			}, "$tmp$pydir";
		}
		
		# Go for the dependencies
		addsubstvar($package, "python:Depends", $pyver) if $verdeps{$pyver};

		# And now, the postinst and prerm stuff
		if ($pyver eq "python$python_version") {
			if ($verdeps{$pyver} & PY_MODULE) {
				$pydir = $pydir.$dirlist;
			} else {
				$pydir = $dirlist;
			}
			$verdeps{$pyver} |= PY_MODULE if($deps & PY_MODULE);
		}
		if ($verdeps{$pyver} & PY_MODULE && ! $dh{NOSCRIPTS}) {
			autoscript($package,"postinst","postinst-python","s%#PYVER#%$pyver%;s%#DIRLIST#%$pydir%");
			$need_prerm = 1;
		}
	}
	if ($need_prerm && ! $dh{NOSCRIPTS}) {
		autoscript($package,"prerm","prerm-python","s%#PACKAGE#%$package%");
	}
}

=head1 SEE ALSO

L<debhelper(7)>

This program is a part of debhelper.

=head1 AUTHOR

Josselin Mouette <joss@debian.org>

most ideas stolen from Brendan O'Dea <bod@debian.org>

=cut