home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / bin / dh_pycentral < prev    next >
Encoding:
Text File  |  2007-04-10  |  21.2 KB  |  713 lines

  1. #!/usr/bin/perl -w
  2.  
  3. =head1 NAME
  4.  
  5. dh_pycentral - use the python-central framework to handle Python modules and extensions
  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_pycentral> [S<I<debhelper options>>] [B<-n>] [B<-X>I<item>] [B<-V> I<version>] [S<I<module dirs ...>>]
  16.  
  17. =head1 DESCRIPTION
  18.  
  19. dh_pycentral is a debhelper program that will scan your package, detect
  20. public Python modules and move them in /usr/share/pycentral so that
  21. python-central can byte-compile those for all supported Python versions.
  22. Extensions are kept into the original installation location.
  23.  
  24. Moving the files to the pycentral location can be disabled by setting
  25. the environment varibale DH_PYCENTRAL to a string containing the
  26. string B<nomove>.
  27.  
  28. You must have filled the XS-Python-Version header to indicate the
  29. set of python versions that are going to be supported. dh_pycentral
  30. expects the XB-Python-Version for each binary package it is supposed
  31. to work on.
  32.  
  33. dh_pycentral will also generate substitution variables: the
  34. ${python:Provides} variable will contain versioned provides of the package
  35. (if the package's name starts with "python-"). A python-foo package could
  36. provide "python2.3-foo" and "python2.4-foo" at the same time. Python
  37. extensions have to provide those whereas it's only option for pure python
  38. modules.
  39.  
  40. The ${python:Versions} variable should be used to provide the required
  41. XB-Python-Version field listing the python versions supported by the
  42. package.
  43.  
  44. =head1 OPTIONS
  45.  
  46. =over 4
  47.  
  48. =item I<module dirs>
  49.  
  50. If your package installs python modules in non-standard directories, you
  51. can make dh_pycentral check those directories by passing their names on the
  52. command line. By default, it will check /usr/lib/$PACKAGE, /usr/share/$PACKAGE, /usr/lib/games/$PACKAGE,
  53. /usr/share/games/$PACKAGE and /usr/lib/python?.?/site-packages.
  54.  
  55. Note: only /usr/lib/python?.?/site-packages and the
  56. extra names on the command line are searched for binary (.so) modules.
  57.  
  58. =item B<-V> I<version>
  59.  
  60. If the .py files your package ships are meant to be used by a specific
  61. pythonX.Y version, you can use this option to specify the desired version,
  62. such as 2.3. Do not use if you ship modules in /usr/lib/site-python.
  63.  
  64. With the new policy, this option is mostly deprecated. Use the
  65. XS-Python-Field to indicate that you're using a specific python version.
  66.  
  67. =item B<-n>, B<--noscripts>
  68.  
  69. Do not modify postinst/postrm scripts.
  70.  
  71. =item B<-X>I<item>, B<--exclude=>I<item>
  72.  
  73. Exclude files that contain "item" anywhere in their filename from being
  74. taken into account to generate the python dependency. You may use this
  75. option multiple times to build up a list of things to exclude.
  76.  
  77. =back
  78.  
  79. =head1 CONFORMS TO
  80.  
  81. Python policy, version 0.4.1 (2006-06-20)
  82.  
  83. =cut
  84.  
  85. init();
  86.  
  87. my $python = 'python';
  88.  
  89. # The current python major version
  90. my $python_major;
  91. my $python_version = `$python -V 2>&1`;
  92. if (! defined $python_version || $python_version eq "") {
  93.     error("Python is not installed, aborting. (Probably forgot to Build-Depend on python.)");
  94. }
  95. elsif ($python_version =~ m/^Python\s+(\d+)\.(\d+)(\.\d+)*/) {
  96.     $python_version = "$1.$2" ;
  97.     $python_major = $1 ;
  98. } else { 
  99.     error("Unable to parse python version out of \"$python_version\".");
  100. }
  101.  
  102. # The next python version
  103. my $python_nextversion = next_minor_version($python_version);
  104. my $python_nextmajor = $python_major + 1;
  105.  
  106. my @python_allversions = ('1.5','2.1','2.2','2.3','2.4','2.5','2.6');
  107. foreach (@python_allversions) {
  108.     s/^/python/;
  109. }
  110.  
  111. # Check for -V
  112. my $usepython = "python$python_version";
  113. if($dh{V_FLAG_SET}) {
  114.     $usepython = $dh{V_FLAG};
  115.     $usepython =~ s/^/python/;
  116.     if (! grep { $_ eq $usepython } @python_allversions) {
  117.         error("Unknown python version $dh{V_FLAG}");
  118.     }
  119. }
  120.  
  121. # Cleaning the paths given on the command line
  122. foreach (@ARGV) {
  123.     s#/$##;
  124.     s#^/##;
  125. }
  126.  
  127. # Check the compatibilty mode to use
  128. my $pyversions_field = "";
  129. my $python_header = "";
  130. {
  131.     local $/ = ""; # Grab until empty line
  132.     open(CONTROL, "debian/control"); # Can't fail, dh_testdir has already been called
  133.     my $source = <CONTROL>;
  134.     close(CONTROL);
  135.     if ($source =~ m/^XS-Python-Version: \s*(.*)$/m) {
  136.         $python_header = $1;
  137.         chomp($python_header);
  138.         $pyversions_field = convert_python_header($python_header);
  139.     }
  140. }
  141.  
  142. # pyversions describes the list of python versions that this package can
  143. # work with
  144. if (-e "debian/pyversions") {
  145.     open(PYVERS, "debian/pyversions") || error("Can't open debian/pyversions: $!");
  146.     $pyversions_field = <PYVERS>;
  147.     chomp($pyversions_field);
  148.     close(PYVERS);
  149. }
  150. verbose_print("Pyversions field: $pyversions_field");
  151.  
  152. # Extract a list of officially supported Python versions
  153. my %officially_supported;
  154. if (-e "/usr/share/python/debian_defaults") {
  155.     open(DEFAULTS, "/usr/share/python/debian_defaults") ||
  156.         error("Can't open /usr/share/python/debian_defaults: $!");
  157.     foreach (<DEFAULTS>) {
  158.         if (/^supported-versions\s*=\s*(.*)$/) {
  159.             my $supported = $1;
  160.             foreach my $version (split(/\s+/, $supported)) {
  161.                 if ($version =~ /python([\d\.]+)/) {
  162.                     $officially_supported{$1} = 1;
  163.                 }
  164.             }
  165.             last;
  166.         }
  167.     }
  168.     close(DEFAULTS);
  169. }
  170.  
  171. # dependency types
  172. use constant PROGRAM   => 1;
  173. use constant PY_PRIVATE_MODULE => 2;
  174. use constant PY_PUBLIC_MODULE => 4;
  175. use constant PY_OFFICIAL_MODULE => 8;
  176. use constant PY_UNKNOWN_MODULE => 16;
  177. use constant SO_PRIVATE_MODULE => 32;
  178. use constant SO_PUBLIC_MODULE => 64;
  179. use constant SO_OFFICIAL_MODULE => 128;
  180. use constant SO_UNKNOWN_MODULE => 256;
  181.  
  182. foreach my $package (@{$dh{DOPACKAGES}}) {
  183.     my $tmp = tmpdir($package);
  184.  
  185.     # Move *.py files if needed
  186.     doit("pycentral debhelper $package $tmp");
  187.  
  188.     # Check that we have *.py files!
  189.     my $found = 0;
  190.     find sub {
  191.         return if $File::Find::dir =~ m|^$tmp/usr/share/doc/|;
  192.         return unless -f and /\.py$/;
  193.         $found++;
  194.     }, $tmp;
  195.  
  196.     if ($found or -d "$tmp/usr/share/pycentral") {
  197.                 addsubstvar($package, "python:Depends", "python-central", ">= 0.5.8");
  198.                 if (! $dh{NOSCRIPTS}) {
  199.                         autoscript($package,"postinst","postinst-pycentral","s%#PACKAGE#%$package%");
  200.                         autoscript($package,"prerm","prerm-pycentral","s%#PACKAGE#%$package%");
  201.                 }
  202.     }
  203.  
  204.     # Here we're doing what dh_python used to do
  205.     my @dirs = ("usr/lib/$package", "usr/share/$package", "usr/lib/games/$package", "usr/share/games/$package", @ARGV );
  206.     my @dirs_so = (@ARGV);
  207.  
  208.     my $dep_on_python = 0;
  209.     my $strong_dep = 0;
  210.  
  211.     # Fail early if the package use usr/lib/site-python
  212.     if (-d "$tmp/usr/lib/site-python") {
  213.         error("The package $package puts files in /usr/lib/site-python: forbidden by policy");
  214.     }
  215.  
  216.     @dirs = grep -d, map "$tmp/$_", @dirs;
  217.     @dirs_so = grep -d, map "$tmp/$_", @dirs_so;
  218.  
  219.     my $deps = 0;
  220.     my %verdeps = ();
  221.     foreach (@python_allversions) {
  222.         $verdeps{$_} = 0;
  223.     }
  224.  
  225.     # Global scan
  226.     my $private_pydirs_regex = join('|', map { "\Q$_\E" } @dirs);
  227.     my $private_sodirs_regex = join('|', map { "\Q$_\E" } @dirs_so);
  228.     my %private_dirs_list;
  229.     my %pyversions_found;
  230.     find sub {
  231.         return unless -f;
  232.         # See if we were asked to exclude this file.
  233.         # Note that we have to test on the full filename, including directory.
  234.         my $fn="$File::Find::dir/$_";
  235.         if (excludefile($fn)) {
  236.             verbose_print("Ignoring $fn");
  237.             return;
  238.         }
  239.         # Find scripts
  240.         if (-x or /\.py$/) {
  241.             local *F;
  242.             return unless open F, $_;
  243.             if (read F, local $_, 32 and m%^#!\s*/usr/bin/(env\s+)?(python(\d+\.\d+)?)\s%) {
  244.                 verbose_print("Found program using $2: $fn");
  245.                 if ( "python" eq $2 ) {
  246.                     $deps |= PROGRAM;
  247.                 } elsif(defined $verdeps{$2}) {
  248.                     $verdeps{$2} |= PROGRAM;
  249.                 }
  250.             }
  251.             close F;
  252.         }
  253.         # Continue only with .py or .so
  254.         return unless (/\.py$/ or /\.so$/);
  255.  
  256.         # Remove any byte-compiled file
  257.         doit(("rm","-f",$_."c",$_."o")) if /\.py$/;
  258.         
  259.         # Classify the file in the right category
  260.         if (/\.py$/ and $private_pydirs_regex and $fn =~ m/(?:$private_pydirs_regex)/) {
  261.             # Private python module
  262.             verbose_print("Found private module: $fn");
  263.             my $dir;
  264.             foreach $dir (@dirs) {
  265.                 if ($fn =~ m/\Q$dir\E/) {
  266.                     $dir =~ s/^$tmp//;
  267.                     verbose_print("Memorizing dir to byte-compile: $dir");
  268.                     $private_dirs_list{"$dir"} = 1;
  269.                 }
  270.             }
  271.             if ($dh{V_FLAG_SET}) {
  272.                 $verdeps{$usepython} |= PY_PRIVATE_MODULE;
  273.             } else {
  274.                 $deps |= PY_PRIVATE_MODULE;
  275.             }
  276.         } elsif (/\.so$/ and $private_sodirs_regex and $fn =~ m/(?:$private_sodirs_regex)/) {
  277.             # Private python extension
  278.             verbose_print("Found private extension: $fn");
  279.             if ($dh{V_FLAG_SET}) {
  280.                 $verdeps{$usepython} |= SO_PRIVATE_MODULE;
  281.             } else {
  282.                 $deps |= SO_PRIVATE_MODULE;
  283.             }
  284.         } elsif ($fn =~ m|$tmp/usr/lib/python([\d\.]+)/site-packages/|) {
  285.             $pyversions_found{$1} = 1;
  286.             my $v = $1;
  287.             if (/\.py$/) {
  288.                 verbose_print("Found public module: $fn");
  289.                 $verdeps{"python$v"} |= PY_PUBLIC_MODULE;
  290.             } else {
  291.                 verbose_print("Found public extension: $fn");
  292.                 $verdeps{"python$v"} |= SO_PUBLIC_MODULE;
  293.             }
  294.         } elsif ($fn =~ m|$tmp/usr/lib/python([\d\.]+)/|) {
  295.             $pyversions_found{$1} = 1;
  296.             my $v = $1;
  297.             if (/\.py$/) {
  298.                 verbose_print("Found official module: $fn");
  299.                 $verdeps{"python$v"} |= PY_OFFICIAL_MODULE;
  300.             } else {
  301.                 verbose_print("Found official extension: $fn");
  302.                 $verdeps{"python$v"} |= SO_OFFICIAL_MODULE;
  303.             }
  304.         } elsif ($fn =~ m|$tmp/usr/lib/python-support/[^/]+/python([\d\.]+)/|) {
  305.             $pyversions_found{$1} = 1;
  306.             my $v = $1;
  307.             if (/\.py$/) {
  308.                 verbose_print("Found public module: $fn");
  309.                 $verdeps{"python$v"} |= PY_PUBLIC_MODULE;
  310.             } else {
  311.                 verbose_print("Found public extension: $fn");
  312.                 $verdeps{"python$v"} |= SO_PUBLIC_MODULE;
  313.             }
  314.         } elsif ($fn =~ m{$tmp(?:/usr/share/pycentral/|/usr/share/python-support/)}) {
  315.             if (/\.py$/) {
  316.                 verbose_print("Found public module: $fn");
  317.                 $deps |= PY_PUBLIC_MODULE;
  318.             } # No extensions here
  319.         } elsif ($fn =~ m|$tmp/usr/lib/python([\d\.]+)/site-packages/|) {
  320.             
  321.         } elsif ($fn =~ m|$tmp/usr/share/doc/|) {
  322.             # Ignore .py files in doc directory
  323.         } else {
  324.             # Unknown pyfiles
  325.             if (/\.py$/) {
  326.                 verbose_print("Found unclassified module: $fn");
  327.                 if ($dh{V_FLAG_SET}) {
  328.                     $verdeps{$usepython} |= PY_UNKNOWN_MODULE;
  329.                 } else {
  330.                     $deps |= PY_UNKNOWN_MODULE;
  331.                 }
  332.             } else {
  333.                 verbose_print("Found unclassified extension: $fn");
  334.                 if ($dh{V_FLAG_SET}) {
  335.                     $verdeps{$usepython} |= SO_UNKNOWN_MODULE;
  336.                 } else {
  337.                     $deps |= SO_UNKNOWN_MODULE;
  338.                 }
  339.             }
  340.         }
  341.     }, $tmp;
  342.  
  343.     #
  344.     # NEW POLICY
  345.     #
  346.     # Generate the depends to accept all python
  347.     # versions that this package effectively provides
  348.     my ($min_version, $max_version, @versions) = analyze_pyversions($pyversions_field);
  349.     my $stop_version = "";
  350.     $stop_version = next_minor_version($max_version) if $max_version;
  351.     my $versions_field = "";
  352.     verbose_print("Pyversions analysis gives: min=$min_version, max=$max_version (@versions)");
  353.  
  354.     # Common dependency handling
  355.     foreach my $pyver (keys %verdeps) {
  356.         # Always add pythonX.Y dependency if a script uses that interpreter
  357.         if ($verdeps{$pyver} & PROGRAM) {
  358.             addsubstvar($package, "python:Depends", $pyver);
  359.         }
  360.         # Always add pythonX.Y dependency if some private modules are
  361.         # byte-compiled with it (or if extensions are
  362.         # byte-compiled with it)
  363.         if ($verdeps{$pyver} & (PY_PRIVATE_MODULE|SO_PRIVATE_MODULE)) {
  364.             addsubstvar($package, "python:Depends", $pyver);
  365.             unless ($versions_field) {
  366.                 $versions_field = $pyver;
  367.                 $versions_field =~ s/^python//;
  368.             }
  369.         }
  370.     }
  371.  
  372.     # Reset again, analysis using new policy follows
  373.     $dep_on_python = 0;
  374.  
  375.     # Private extensions, must be rebuilt for each python version
  376.     if ($deps & SO_PRIVATE_MODULE) {
  377.         if (($dh{V_FLAG_SET} and ($usepython eq "python$python_version")) or
  378.             (($min_version eq $python_version) and ($min_version eq $max_version))
  379.            ) {
  380.             # Depend on python only if the version
  381.             # used to build is the currently supported one
  382.             $dep_on_python++;
  383.         } 
  384.         # Packages using a private extension can only support one
  385.         # version: if versions_field is already set that's because
  386.         # we're using -V and we should respect that, otherwise try
  387.         # the best guess:
  388.         unless($versions_field) {
  389.             if ($min_version and ($min_version eq $max_version)) {
  390.                 # Only one version supported, use it
  391.                 $versions_field = $min_version;
  392.             } elsif (compare_version($min_version, $python_version) > 0) {
  393.                 # The current version is unsupported, use the min version instead
  394.                 $versions_field = $min_version;
  395.             } else {
  396.                 # Use the current version by default
  397.                 $versions_field = $python_version;
  398.                 $min_version = $python_version;
  399.             }
  400.         }
  401.         $stop_version = next_minor_version($versions_field);
  402.     } 
  403.  
  404.     # Private modules 
  405.     if ($deps & PY_PRIVATE_MODULE) {
  406.         # Package with private modules can only support one version at a time
  407.         # (even if the modules can be automatically byte-compiled for any new
  408.         # python version).
  409.         unless ($versions_field) {
  410.             # Unless min/max are the same we put "current"
  411.             if ($min_version and ($min_version eq $max_version)) {
  412.                 $versions_field = $min_version;
  413.             } elsif (compare_version($min_version, $python_version) > 0) {
  414.                 # The current version is unsupported, use the min version instead
  415.                 $versions_field = $min_version;
  416.             } else {
  417.                 # Use the current version by default
  418.                 $versions_field = "current";
  419.             }
  420.         }
  421.     }
  422.  
  423.     # Python scripts & public modules
  424.     if ($deps & (PROGRAM|PY_PUBLIC_MODULE)) {
  425.         $dep_on_python++;
  426.     }
  427.     
  428.     # Public extensions
  429.     if (scalar keys %pyversions_found) {
  430.         # Extensions will always trigger this (as well as public
  431.         # modules not handled by python-support/python-central)
  432.         $dep_on_python++;
  433.         if (scalar grep { $python_version eq $_ } keys %pyversions_found) {
  434.             # Current versions is supported by the package
  435.             # It's safe to depends on the corresponding
  436.             # interval of python versions
  437.             $min_version = min(keys %pyversions_found);
  438.             unless ($stop_version) {
  439.                 $max_version = max(keys %pyversions_found);
  440.                 $stop_version = next_minor_version($max_version);
  441.             }
  442.         } else {
  443.             # Current version is not supported by the package
  444.             if ($min_version and ($min_version eq $max_version)) {
  445.                 # If we support only one non-standard python
  446.                 # version, the depend on that version and not on python
  447.                 $dep_on_python--;
  448.                 if (! $dep_on_python) {
  449.                     addsubstvar($package, "python:Depends", "python$min_version");
  450.                 }
  451.             }
  452.         }
  453.         # Generate the Python-Version field
  454.         foreach (keys %pyversions_found) {
  455.             addsubstvar($package, "python:Versions", $_);
  456.         }
  457.         # Generate provides for the python2.X-foo packages that we emulate
  458.         if ($package =~ /^python-/) {
  459.             foreach (keys %pyversions_found) {
  460.                 my $virtual = $package;
  461.                 $virtual =~ s/^python-/$python$_-/;
  462.                 addsubstvar($package, "python:Provides", $virtual);
  463.             }
  464.         }
  465.     } else {
  466.         # Still try to describe the versions that the package support
  467.         $versions_field = $python_header unless $versions_field;
  468.         $versions_field = "all" unless $versions_field;
  469.         addsubstvar($package, "python:Versions", $versions_field);
  470.  
  471.         # Generate provides for all python versions supported
  472.         if ($package =~ /^python-/) {
  473.             foreach (grep { $officially_supported{$_} } @versions) {
  474.                 my $virtual = $package;
  475.                 $virtual =~ s/^python-/$python$_-/;
  476.                 addsubstvar($package, "python:Provides", $virtual);
  477.             }
  478.         }
  479.     }
  480.     
  481.     if ($dep_on_python) {
  482.         # At least a script has been detected
  483.         if ($min_version) {
  484.             if (compare_version($min_version, $python_version) <= 0 ) {
  485.                 # Min-version is less or equal to current version
  486.                 addsubstvar($package, "python:Depends", $python, ">= $min_version");
  487.             } else {
  488.                 # Min version is greater to current version
  489.                 # Supposition: new stuff working only with the latest python, 
  490.                 # depend on that specific python version
  491.                 addsubstvar($package, "python:Depends", 
  492.                         "python (>= $min_version) | python$min_version");
  493.             }
  494.         }
  495.         # If a stronger dependency is needed
  496.         if ($stop_version) {
  497.             if (compare_version($stop_version, $python_version) > 0 ) {
  498.                 # Stop version is strictly bigger than current version
  499.                 addsubstvar($package, "python:Depends", $python, "<< $stop_version");
  500.             } else {
  501.                 # Only works with old versions,
  502.                 # package is mostly deprecated,
  503.                 # no need for a python dependency
  504.             }
  505.         }
  506.         # Let's depend on python anyway
  507.         addsubstvar($package, "python:Depends", $python) unless ($min_version or $stop_version);
  508.     }
  509. }
  510.  
  511. sub next_minor_version {
  512.     my $version = shift;
  513.     # Handles 2.10 -> 2.11 gracefully
  514.     my @items = split(/\./, $version);
  515.     $items[1] += 1;
  516.     $version = join(".", @items);
  517.     return $version;
  518. }
  519.  
  520. sub compare_version {
  521.     my ($a, $b) = @_;
  522.     my @A = split(/\./, $a);
  523.     my @B = split(/\./, $b);
  524.     my $diff = 0;
  525.     for (my $i = 0; $i <= $#A; $i++) {
  526.     $diff = $A[$i] - $B[$i];
  527.     return $diff if $diff; 
  528.     }
  529.     # They are the same
  530.     return 0;
  531. }
  532.  
  533. sub max {
  534.     my $max = shift;
  535.     foreach (@_) {
  536.     $max = $_ if (compare_version($_, $max) > 0);
  537.     }
  538.     return $max;
  539. }
  540.  
  541. sub min {
  542.     my $min = shift;
  543.     foreach (@_) {
  544.     $min = $_ if (compare_version($_, $min) < 0);
  545.     }
  546.     return $min;
  547. }
  548.  
  549. # Extract min, max and list of versions from
  550. # a string like this "-1.2,1.4-1.6,2.0,2.3-"
  551. sub analyze_pyversions {
  552.     my $field = shift;
  553.     my ($min, $max, @versions);
  554.  
  555.     my @all_versions = ("0.0");
  556.     foreach (@python_allversions) {
  557.     if (m/python([\d\.]+)/) {
  558.         push @all_versions, $1;
  559.     }
  560.     }
  561.     push @all_versions, "100.0";
  562.  
  563.     foreach my $range (split /,/, $field) {
  564.     if ($range =~ /^([\d\.]+)?-([\d\.]+)?$/) {
  565.         $min = defined($1) && $1 ? $1 : "0.0";
  566.         $max = defined($2) && $2 ? $2 : "100.0";
  567.         push @versions, grep { 
  568.         compare_version($_, $min) >= 0 and 
  569.         compare_version($_, $max) <= 0 } @all_versions;
  570.     } else {
  571.         push @versions, $range if (grep { $range eq $_ } @all_versions);
  572.     }
  573.     }
  574.  
  575.     $min = min(@versions);
  576.     $max = max(@versions);
  577.     $min = "" if (!defined($min) or $min eq "0.0");
  578.     $max = "" if (!defined($max) or $max eq "100.0");
  579.  
  580.     @versions = grep { $_ ne "0.0" and $_ ne "100.0" } @versions;
  581.  
  582.     return ($min, $max, @versions);
  583. }
  584.  
  585. # Convert the Python-Version field in a standardized "pyversions" field
  586. sub convert_python_header {
  587.     my $header = shift;
  588.     my %pyversions_expected;
  589.     my %pyversions_additional;
  590.     my $use_additional = 0;
  591.     my @all_versions = ();
  592.     foreach (@python_allversions) {
  593.     if (m/python([\d\.]+)/) {
  594.         $pyversions_additional{$1} = 1;
  595.         push @all_versions, $1;
  596.     }
  597.     }
  598.     # Add two fakes minima, maxima to check if we have limits
  599.     $pyversions_additional{"0.0"} = 1;
  600.     $pyversions_additional{"100.0"} = 1;
  601.  
  602.     # Compute the list of versions that are supported
  603.     foreach my $check (split(/,\s*/, $header)) {
  604.     if ($check =~ /^=?\s*([\d\.]+)/) {
  605.         # Add any fixed version
  606.         $pyversions_expected{$1} = 1 if (grep { $_ eq $1 } @all_versions);
  607.         next;
  608.     }
  609.     # Deactivate versions which do not match the other
  610.     # criteria
  611.     if ($check =~ /^<<\s*([\d\.]+)/) {
  612.         my $v = $1;
  613.         $use_additional = 1;
  614.         foreach (keys %pyversions_additional) {
  615.         $pyversions_additional{$_} = 0 unless (compare_version($_, $v) < 0);
  616.         }
  617.     } elsif ($check =~ /^<=\s*([\d\.]+)/) {
  618.         my $v = $1;
  619.         $use_additional = 1;
  620.         foreach (keys %pyversions_additional) {
  621.         $pyversions_additional{$_} = 0 unless (compare_version($_, $v) <= 0);
  622.         }
  623.     } elsif ($check =~ /^>=\s*([\d\.]+)/) {
  624.         my $v = $1;
  625.         $use_additional = 1;
  626.         foreach (keys %pyversions_additional) {
  627.         $pyversions_additional{$_} = 0 unless (compare_version($_, $v) >= 0);
  628.         }
  629.     }
  630.     }
  631.     if ($use_additional) {
  632.     foreach (grep { $pyversions_additional{$_} } keys %pyversions_additional) {
  633.         $pyversions_expected{$_} = 1;
  634.     }
  635.     }
  636.  
  637.     my @supported = sort { compare_version($a, $b) } 
  638.             grep { $pyversions_expected{$_} == 1 } keys %pyversions_expected;
  639.     
  640.     verbose_print("List of versions supported according to XS-Python-Version: @supported");
  641.  
  642.     # Generate the corresponding information in standardized "pyversions" format
  643.     # XXX: I go to great length to generate the shortest pyversions
  644.     # syntax but it may not be necessary for the usage that we make of it.
  645.     my ($result, $index, $range_is_open, $last_real_version) = ("", 0, 0, "");
  646.     foreach (@supported) {
  647.     if ($_ eq "0.0") {
  648.         $result .= "-"; # No lower limit
  649.         $range_is_open = 1;
  650.     } elsif ($_ eq "100.0") {
  651.         $result .= "-" unless $range_is_open; # No upper limit
  652.         $range_is_open = 0; # Proper end
  653.     } else {
  654.         $last_real_version = $_;
  655.         if ($range_is_open) {
  656.         # Range is open
  657.         if ($index <= $#all_versions and $all_versions[$index] eq $_) {
  658.             # This version still in the range
  659.         } else {
  660.             # Previous version ended the range
  661.             $result .= $all_versions[$index-1] . ",$_";
  662.             $range_is_open = 0;
  663.         }
  664.         # Find the current version in all_versions
  665.         while ($index <= $#all_versions) {
  666.             last if ($all_versions[$index] eq $_);
  667.             $index++;
  668.         }
  669.         } else {
  670.         # There's no range yet
  671.         if ($result) {
  672.             if ($index <= $#all_versions and $all_versions[$index] eq $_) {
  673.             # This version still match, we can start a range
  674.             $result .= "-";
  675.             $range_is_open = 1;
  676.             } else {
  677.             # Next version doesn't match, no range but a list
  678.             $result .= ",$_";
  679.             }
  680.         } else {
  681.             # Empty field, start with something!
  682.             $result = "$_";
  683.         }
  684.         while ($index <= $#all_versions) {
  685.             last if ($all_versions[$index] eq $_);
  686.             $index++;
  687.         }
  688.         }
  689.         $index++;
  690.     }
  691.     }
  692.     if ($range_is_open) {
  693.     # Close the range properly
  694.     $result .= $last_real_version;
  695.     }
  696.     return $result;
  697. }
  698.  
  699. =head1 SEE ALSO
  700.  
  701. L<debhelper(7)>
  702.  
  703. This program is a part of python-central but is made to work with debhelper.
  704.  
  705. =head1 AUTHORS
  706.  
  707. Raphael Hertzog <hertzog@debian.org>
  708.  
  709. Also includes bits of the old dh_python written by Josselin Mouette
  710. <joss@debian.org> who used many ideas from Brendan O'Dea <bod@debian.org>.
  711.  
  712. =cut
  713.