#!/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>] [B<-X>I<item>] [B<-V> I<version>] [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 adequate dependencies. Additionally,
it will also use debian/pyversions as a list of python versions that the
package is known to support. That file contains a single line with a
comma delimited list of python versions in the format "X.Y". You can
specify ranges of python versions with "W.X-Y.Z". You can omit one side of
the range like in "X.Y-" or "-X.Y" which will respectively indicate all
python versions greater or equal to "X.Y" or smaller or equal to "X.Y".

In order to support two different Python policies, dh_python looks for
an environment variable DH_PYCOMPAT or the file debian/pycompat. The
content of those is a single number representing the compatibility mode
that will be used by dh_python. This number can be 1 or 2. 

In both modes, the ${python:Depends} variable contains appropriate
dependencies on python or pythonX.Y.

=head2 Compatibility level 2 (new policy)

dh_python will only generate substitution variables, it won't take care of
the byte-compilation of modules any more.

The ${python:Provides} variable will contain versioned provides of the
package (if the package's name starts with "python-"). A python-foo
package could provide "python2.3-foo" and "python2.4-foo" at the same
time. Python extensions have to provide those whereas it's only option
for pure python modules.

The ${python:Versions} variable can be used to provide an optional
XB-Python-Version field listing the python versions supported by the
package.

=head2 Compatibility level 1 (old policy)

It looks at scripts and modules in your package and adds 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 already byte-compiled
modules are found, they are removed.

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

Note: in the old policy, /usr/lib/site-python is also scanned for modules.

=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/$PACKAGE, /usr/share/$PACKAGE, /usr/lib/games/$PACKAGE,
/usr/share/games/$PACKAGE and /usr/lib/python?.?/site-packages.

Note: only /usr/lib/python?.?/site-packages and the
extra names on the command line are searched for binary (.so) modules.

=item B<-V> I<version>

If the .py files your package ships are meant to be used by a specific
pythonX.Y version, you can use this option to specify the desired version,
such as 2.3. Do not use if you ship modules in /usr/lib/site-python.

With the new policy, this option is mostly deprecated. Use the
XS-Python-Field to indicate that you're using a specific python version.

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

Do not modify postinst/postrm scripts.

=item B<-X>I<item>, B<--exclude=>I<item>

Exclude files that contain "item" anywhere in their filename from being
taken into account to generate the python dependency. You may use this
option multiple times to build up a list of things to exclude.

=back

=head1 CONFORMS TO

Debian policy, version 3.7.2

Python policy, version 0.4.1 (2006-06-20)

=cut

init();

my $python = 'python';

# The current python major version
my $python_major;
my $python_version = `$python -V 2>&1`;
if (! defined $python_version || $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 = next_minor_version($python_version);
my $python_nextmajor = $python_major + 1;

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

# Check for -V
my $usepython = "python$python_version";
if($dh{V_FLAG_SET}) {
	$usepython = $dh{V_FLAG};
	$usepython =~ s/^/python/;
	if (! grep { $_ eq $usepython } @python_allversions) {
		error("Unknown python version $dh{V_FLAG}");
	}
}

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

# Check the compatibilty mode to use
my $compat_mode = "";
my $pyversions_field = "";
my $python_header = "";
{
	local $/ = ""; # Grab until empty line
	open(CONTROL, "debian/control"); # Can't fail, dh_testdir has already been called
	my $source = <CONTROL>;
	close(CONTROL);
	if ($source =~ m/^XS-Python-Version: \s*(.*)$/m) {
		$python_header = $1;
		chomp($python_header);
		$pyversions_field = convert_python_header($python_header);
		$compat_mode = 2 unless $compat_mode; #
	}
}
if (defined($ENV{DH_PYCOMPAT})) {
	$compat_mode = $ENV{DH_PYCOMPAT};
} elsif (-e "debian/pycompat") {
	open (COMPAT_IN, "debian/pycompat") || error "debian/pycompat: $!";
	my $l=<COMPAT_IN>;
	chomp $l;
	if ($l) {
		$compat_mode = $l
	} else {
		warning("debian/pycompat is empty, assuming dh_python compatibility level 1");
	}
}
$compat_mode = 1 unless $compat_mode; # Default to old policy
error("Maximum dh_python compatibility mode supported is 2.") if $compat_mode > 2;

# pyversions describes the list of python versions that this package can
# work with
if (-e "debian/pyversions") {
	open(PYVERS, "debian/pyversions") || error("Can't open debian/pyversions: $!");
	$pyversions_field = <PYVERS>;
	chomp($pyversions_field);
	close(PYVERS);
}
verbose_print("Pyversions field: $pyversions_field");

# Extract a list of officially supported Python versions
my %officially_supported;
if (-e "/usr/share/python/debian_defaults") {
	open(DEFAULTS, "/usr/share/python/debian_defaults") ||
	    error("Can't open /usr/share/python/debian_defaults: $!");
	foreach (<DEFAULTS>) {
		if (/^supported-versions\s*=\s*(.*)$/) {
			my $supported = $1;
			foreach my $version (split(/\s+/, $supported)) {
				if ($version =~ /python([\d\.]+)/) {
				    $officially_supported{$1} = 1;
				}
			}
			last;
		}
	}
	close(DEFAULTS);
}

# dependency types
use constant PROGRAM   => 1;
use constant PY_PRIVATE_MODULE => 2;
use constant PY_PUBLIC_MODULE => 4;
use constant PY_OFFICIAL_MODULE => 8;
use constant PY_UNKNOWN_MODULE => 16;
use constant SO_PRIVATE_MODULE => 32;
use constant SO_PUBLIC_MODULE => 64;
use constant SO_OFFICIAL_MODULE => 128;
use constant SO_UNKNOWN_MODULE => 256;

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

	my @dirs = ("usr/lib/$package", "usr/share/$package", "usr/lib/games/$package", "usr/share/games/$package", @ARGV );
	my @dirs_so = (@ARGV);

	my $dep_on_python = 0;
	my $strong_dep = 0;

	# Fail early if the package use usr/lib/site-python
	if (-d "$tmp/usr/lib/site-python") {
		if ($compat_mode >= 2) {
			# Error only on new policy
			error("The package $package puts files in /usr/lib/site-python: forbidden by policy");
		} else {
			# Old policy allowed that directory, so scan it
			push @dirs, "usr/lib/site-python";
			push @dirs_so, "usr/lib/site-python";
		}
	}

	@dirs = grep -d, map "$tmp/$_", @dirs;
	@dirs_so = grep -d, map "$tmp/$_", @dirs_so;

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

	# Global scan
	my $private_pydirs_regex = join('|', map { "\Q$_\E" } @dirs);
	my $private_sodirs_regex = join('|', map { "\Q$_\E" } @dirs_so);
	my %private_dirs_list;
	my %pyversions_found;
	find sub {
		return unless -f;
		# See if we were asked to exclude this file.
		# Note that we have to test on the full filename, including directory.
		my $fn="$File::Find::dir/$_";
		if (excludefile($fn)) {
			verbose_print("Ignoring $fn");
			return;
		}
		# Find scripts
		if (-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;
		}
		# Continue only with .py or .so
		return unless (/\.py$/ or /\.so$/);

		# Remove any byte-compiled file
		doit(("rm","-f",$_."c",$_."o")) if /\.py$/;
		
		# Classify the file in the right category
		if (/\.py$/ and $private_pydirs_regex and $fn =~ m/(?:$private_pydirs_regex)/) {
			# Private python module
			verbose_print("Found private module: $fn");
			my $dir;
			foreach $dir (@dirs) {
				if ($fn =~ m/\Q$dir\E/) {
					$dir =~ s/^$tmp//;
					verbose_print("Memorizing dir to byte-compile: $dir");
					$private_dirs_list{"$dir"} = 1;
				}
			}
			if ($dh{V_FLAG_SET}) {
				$verdeps{$usepython} |= PY_PRIVATE_MODULE;
			} else {
				$deps |= PY_PRIVATE_MODULE;
			}
		} elsif (/\.so$/ and $private_sodirs_regex and $fn =~ m/(?:$private_sodirs_regex)/) {
			# Private python extension
			verbose_print("Found private extension: $fn");
			if ($dh{V_FLAG_SET}) {
				$verdeps{$usepython} |= SO_PRIVATE_MODULE;
			} else {
				$deps |= SO_PRIVATE_MODULE;
			}
		} elsif ($fn =~ m|$tmp/usr/lib/python([\d\.]+)/site-packages/|) {
			$pyversions_found{$1} = 1;
			my $v = $1;
			if (/\.py$/) {
				verbose_print("Found public module: $fn");
				$verdeps{"python$v"} |= PY_PUBLIC_MODULE;
			} else {
				verbose_print("Found public extension: $fn");
				$verdeps{"python$v"} |= SO_PUBLIC_MODULE;
			}
		} elsif ($fn =~ m|$tmp/usr/lib/python([\d\.]+)/|) {
			$pyversions_found{$1} = 1;
			my $v = $1;
			if (/\.py$/) {
				verbose_print("Found official module: $fn");
				$verdeps{"python$v"} |= PY_OFFICIAL_MODULE;
			} else {
				verbose_print("Found official extension: $fn");
				$verdeps{"python$v"} |= SO_OFFICIAL_MODULE;
			}
		} elsif ($fn =~ m|$tmp/usr/lib/python-support/[^/]+/python([\d\.]+)/|) {
			$pyversions_found{$1} = 1;
			my $v = $1;
			if (/\.py$/) {
				verbose_print("Found public module: $fn");
				$verdeps{"python$v"} |= PY_PUBLIC_MODULE;
			} else {
				verbose_print("Found public extension: $fn");
				$verdeps{"python$v"} |= SO_PUBLIC_MODULE;
			}
		} elsif ($fn =~ m{$tmp(?:/usr/share/pycentral/|/usr/share/python-support/)}) {
			if (/\.py$/) {
				verbose_print("Found public module: $fn");
				$deps |= PY_PUBLIC_MODULE;
			} # No extensions here
		} elsif ($fn =~ m|$tmp/usr/lib/python([\d\.]+)/site-packages/|) {
			
		} elsif ($fn =~ m|$tmp/usr/share/doc/|) {
			# Ignore .py files in doc directory
		} else {
			# Unknown pyfiles
			if (/\.py$/) {
				verbose_print("Found unclassified module: $fn");
				if ($dh{V_FLAG_SET}) {
					$verdeps{$usepython} |= PY_UNKNOWN_MODULE;
				} else {
					$deps |= PY_UNKNOWN_MODULE;
				}
			} else {
				verbose_print("Found unclassified extension: $fn");
				if ($dh{V_FLAG_SET}) {
					$verdeps{$usepython} |= SO_UNKNOWN_MODULE;
				} else {
					$deps |= SO_UNKNOWN_MODULE;
				}
			}
		}
	}, $tmp;

	# Common dependency handling
	foreach my $pyver (keys %verdeps) {
		# Always add pythonX.Y dependency if a script uses that interpreter
		if ($verdeps{$pyver} & PROGRAM) {
			addsubstvar($package, "python:Depends", $pyver);
		}
		# Always add pythonX.Y dependency if some private modules are
		# byte-compiled with it (or if extensions are
		# byte-compiled with it)
		if ($verdeps{$pyver} & (PY_PRIVATE_MODULE|SO_PRIVATE_MODULE)) {
			addsubstvar($package, "python:Depends", $pyver);
		}
	}

	if ($compat_mode == 2) {
		#
		# NEW POLICY
		#
		# Generate the depends to accept all python
		# versions that this package effectively provides
		my ($min_version, $max_version, @versions) = analyze_pyversions($pyversions_field);
		my $stop_version = "";
		$stop_version = next_minor_version($max_version) if $max_version;
		my $versions_field = "";
		verbose_print("Pyversions analysis gives: min=$min_version, max=$max_version (@versions)");
		
		# Reset again, analysis using new policy follows
		$dep_on_python = 0;

		# Private extensions, must be rebuilt for each python version
		if ($deps & SO_PRIVATE_MODULE) {
			$dep_on_python++;
			# Packages using a private extension can only
			# support one version
			# Unless min/max are the same we put $python_version
			if ($min_version and ($min_version eq $max_version)) {
				$versions_field = $min_version;
			} else {
				if (compare_version($min_version, $python_version) > 0) {
					# The current version is unsupported, use the min version instead
					$versions_field = $min_version;
				} else {
					# Use the current version by default
					$versions_field = $python_version;
					$min_version = $python_version;
				}
				$stop_version = next_minor_version($versions_field);
			}
		} 

		# Private modules 
		if ($deps & PY_PRIVATE_MODULE) {
			# Package with private modules can only support one version at a time
			# (even if the modules can be automatically byte-compiled for any new
			# python version).
			unless ($versions_field) {
				# Unless min/max are the same we put "current"
				if ($min_version and ($min_version eq $max_version)) {
					$versions_field = $min_version;
				} else {
					$versions_field = "current";
				}
			}
		}

		# Python scripts & public modules
		if ($deps & (PROGRAM|PY_PUBLIC_MODULE)) {
			$dep_on_python++;
		}
		
		# Public extensions
		if (scalar keys %pyversions_found) {
			# Extensions will always trigger this (as well as public
			# modules not handled by python-support/python-central)
			$dep_on_python++;
			if (scalar grep { $python_version eq $_ } keys %pyversions_found) {
				# Current versions is supported by the package
				# It's safe to depends on the corresponding
				# interval of python versions
				$min_version = min(keys %pyversions_found);
				unless ($stop_version) {
				    $max_version = max(keys %pyversions_found);
				    $stop_version = next_minor_version($max_version);
				}
			}
			# Generate the Python-Version field
			foreach (keys %pyversions_found) {
				addsubstvar($package, "python:Versions", $_);
			}
			# Generate provides for the python2.X-foo packages that we emulate
			if ($package =~ /^python-/) {
				foreach (keys %pyversions_found) {
					my $virtual = $package;
					$virtual =~ s/^python-/$python$_-/;
					addsubstvar($package, "python:Provides", $virtual);
				}
			}
		} else {
			# Still try to describe the versions that the package support
			$versions_field = $python_header unless $versions_field;
			$versions_field = "all" unless $versions_field;
			addsubstvar($package, "python:Versions", $versions_field);

			# Generate provides for all python versions supported
			if ($package =~ /^python-/) {
				foreach (grep { $officially_supported{$_} } @versions) {
					my $virtual = $package;
					$virtual =~ s/^python-/$python$_-/;
					addsubstvar($package, "python:Provides", $virtual);
				}
			}
		}
		
		if ($dep_on_python) {
			# At least a script has been detected
			if ($min_version) {
				if (compare_version($min_version, $python_version) <= 0 ) {
					# Min-version is less or equal to current version
					addsubstvar($package, "python:Depends", $python, ">= $min_version");
				} else {
					# Min version is greater to current version
					# Supposition: new stuff working only with the latest python, 
					# depend on that specific python version
					addsubstvar($package, "python:Depends", 
						    "python (>= $min_version) | python$min_version");
				}
			}
			# If a stronger dependency is needed
			if ($stop_version) {
				if (compare_version($stop_version, $python_version) > 0 ) {
					# Stop version is strictly bigger than current version
					addsubstvar($package, "python:Depends", $python, "<< $stop_version");
				} else {
					# Only works with old versions,
					# package is mostly deprecated,
					# no need for a python dependency
				}
			}
			# Let's depend on python anyway
			addsubstvar($package, "python:Depends", $python) unless ($min_version or $stop_version);
		}

	} elsif ($compat_mode == 1) {
		#
		# OLD POLICY
		#

		# First, the case of python-foo and pythonX.Y-foo
		if ($package =~ /^python-/) {
			$dep_on_python = 1;
			$strong_dep = 1;
			# This adds a dependency to python<current>-foo in python-foo
			my $pack = $package;
			$pack =~ s/^python/python$python_version/;
			if (grep { "$_" eq "$pack" } getpackages()) {
				addsubstvar($package, "python:Depends", $pack);
			}
		}

		# Dependencies on current python
		$dep_on_python = 1 if ($deps &
		    (PROGRAM|PY_PUBLIC_MODULE|SO_PUBLIC_MODULE|PY_PRIVATE_MODULE|SO_PRIVATE_MODULE));
		$strong_dep = 1 if ($deps & (PY_PUBLIC_MODULE|SO_PUBLIC_MODULE));

		# Add python dependencies
		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");
			}
		}

		# Add postinst/preinst
		my $need_prerm = 0;
		foreach my $pyver (@python_allversions) {
			my $pydir="/usr/lib/$pyver/site-packages";
			my @dirlist = (); # List of directories to byte-compile

			# If we have public modules, byte-compile /usr/lib/pythonX.Y/site-packages/
			if ($verdeps{$pyver} & PY_PUBLIC_MODULE) {
				push @dirlist, $pydir;
			}
			
			# Byte-compile private modules with current python
			# (or the one indicated by -V)
			if (($pyver eq "$usepython") and scalar(keys %private_dirs_list)) {
				push @dirlist, keys %private_dirs_list;
			}

			# If we have something to byte-compile, add the
			# corresponding postinst snippet
			if (scalar(@dirlist) && ! $dh{NOSCRIPTS}) {
				autoscript($package,"postinst","postinst-python","s%#PYVER#%$pyver%;s%#DIRLIST#%@dirlist%");
				$need_prerm = 1;
			}
		}
		if ($need_prerm && ! $dh{NOSCRIPTS}) {
			autoscript($package,"prerm","prerm-python","s%#PACKAGE#%$package%");
		}
	}
}

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;
}

sub compare_version {
    my ($a, $b) = @_;
    my @A = split(/\./, $a);
    my @B = split(/\./, $b);
    my $diff = 0;
    for (my $i = 0; $i <= $#A; $i++) {
	$diff = $A[$i] - $B[$i];
	return $diff if $diff; 
    }
    # They are the same
    return 0;
}

sub max {
    my $max = shift;
    foreach (@_) {
	$max = $_ if (compare_version($_, $max) > 0);
    }
    return $max;
}

sub min {
    my $min = shift;
    foreach (@_) {
	$min = $_ if (compare_version($_, $min) < 0);
    }
    return $min;
}

# Extract min, max and list of versions from
# a string like this "-1.2,1.4-1.6,2.0,2.3-"
sub analyze_pyversions {
    my $field = shift;
    my ($min, $max, @versions);

    my @all_versions = ("0.0");
    foreach (@python_allversions) {
	if (m/python([\d\.]+)/) {
	    push @all_versions, $1;
	}
    }
    push @all_versions, "100.0";

    foreach my $range (split /,/, $field) {
	if ($range =~ /^([\d\.]+)?-([\d\.]+)?$/) {
	    $min = defined($1) && $1 ? $1 : "0.0";
	    $max = defined($2) && $2 ? $2 : "100.0";
	    push @versions, grep { 
		compare_version($_, $min) >= 0 and 
		compare_version($_, $max) <= 0 } @all_versions;
	} else {
	    push @versions, $range if (grep { $range eq $_ } @all_versions);
	}
    }

    $min = min(@versions);
    $max = max(@versions);
    $min = "" if (!defined($min) or $min eq "0.0");
    $max = "" if (!defined($max) or $max eq "100.0");

    @versions = grep { $_ ne "0.0" and $_ ne "100.0" } @versions;

    return ($min, $max, @versions);
}

# Convert the Python-Version field in a standardized "pyversions" field
sub convert_python_header {
    my $header = shift;
    my %pyversions_expected;
    my %pyversions_additional;
    my $use_additional = 0;
    my @all_versions = ();
    foreach (@python_allversions) {
	if (m/python([\d\.]+)/) {
	    $pyversions_additional{$1} = 1;
	    push @all_versions, $1;
	}
    }
    # Add two fakes minima, maxima to check if we have limits
    $pyversions_additional{"0.0"} = 1;
    $pyversions_additional{"100.0"} = 1;

    # Compute the list of versions that are supported
    foreach my $check (split(/,\s*/, $header)) {
	if ($check =~ /^=?\s*([\d\.]+)/) {
	    # Add any fixed version
	    $pyversions_expected{$1} = 1 if (grep { $_ eq $1 } @all_versions);
	    next;
	}
	# Deactivate versions which do not match the other
	# criteria
	if ($check =~ /^<<\s*([\d\.]+)/) {
	    my $v = $1;
	    $use_additional = 1;
	    foreach (keys %pyversions_additional) {
		$pyversions_additional{$_} = 0 unless (compare_version($_, $v) < 0);
	    }
	} elsif ($check =~ /^<=\s*([\d\.]+)/) {
	    my $v = $1;
	    $use_additional = 1;
	    foreach (keys %pyversions_additional) {
		$pyversions_additional{$_} = 0 unless (compare_version($_, $v) <= 0);
	    }
	} elsif ($check =~ /^>=\s*([\d\.]+)/) {
	    my $v = $1;
	    $use_additional = 1;
	    foreach (keys %pyversions_additional) {
		$pyversions_additional{$_} = 0 unless (compare_version($_, $v) >= 0);
	    }
	}
    }
    if ($use_additional) {
	foreach (grep { $pyversions_additional{$_} } keys %pyversions_additional) {
	    $pyversions_expected{$_} = 1;
	}
    }

    my @supported = sort { compare_version($a, $b) } 
		    grep { $pyversions_expected{$_} == 1 } keys %pyversions_expected;
    
    verbose_print("List of versions supported according to XS-Python-Version: @supported");

    # Generate the corresponding information in standardized "pyversions" format
    # XXX: I go to great length to generate the shortest pyversions
    # syntax but it may not be necessary for the usage that we make of it.
    my ($result, $index, $range_is_open, $last_real_version) = ("", 0, 0, "");
    foreach (@supported) {
	if ($_ eq "0.0") {
	    $result .= "-"; # No lower limit
	    $range_is_open = 1;
	} elsif ($_ eq "100.0") {
	    $result .= "-" unless $range_is_open; # No upper limit
	    $range_is_open = 0; # Proper end
	} else {
	    $last_real_version = $_;
	    if ($range_is_open) {
		# Range is open
		if ($index <= $#all_versions and $all_versions[$index] eq $_) {
		    # This version still in the range
		} else {
		    # Previous version ended the range
		    $result .= $all_versions[$index-1] . ",$_";
		    $range_is_open = 0;
		}
		# Find the current version in all_versions
		while ($index <= $#all_versions) {
		    last if ($all_versions[$index] eq $_);
		    $index++;
		}
	    } else {
		# There's no range yet
		if ($result) {
		    if ($index <= $#all_versions and $all_versions[$index] eq $_) {
			# This version still match, we can start a range
			$result .= "-";
			$range_is_open = 1;
		    } else {
			# Next version doesn't match, no range but a list
			$result .= ",$_";
		    }
		} else {
		    # Empty field, start with something!
		    $result = "$_";
		}
		while ($index <= $#all_versions) {
		    last if ($all_versions[$index] eq $_);
		    $index++;
		}
	    }
	    $index++;
	}
    }
    if ($range_is_open) {
	# Close the range properly
	$result .= $last_real_version;
    }
    return $result;
}

=head1 SEE ALSO

L<debhelper(7)>

This program is a part of debhelper.

=head1 AUTHORS

Josselin Mouette <joss@debian.org>
Raphael Hertzog <hertzog@debian.org>

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

=cut
