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