[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Ending/reducing bytecode compilation, loosening dependencies



Le dimanche 01 janvier 2006 à 16:14 -0600, Joe Wreschnig a écrit :
> > The real fix for this issue isn't to stop generating the .pyc files. It
> > is to make python not generate any .pyc files at all when running as
> > root.
> 
> Well, I would say, not generate any pyc files unless requested,
> regardless of whether or not the user is root. My goal was to propose
> this with minimal changes to the Python code, but I'm also open to doing
> this, of course.

I'd say it depends on whether Matthias agrees with such a change.

> > I can see two ways to go from now for dh_python.
> > 
> > 1. Make, as you suggested, dh_python stop building .pyc files - but only
> > for python-only packages, by default. The former behaviour could be
> > enabled by a flag for modules that are affected enough by the
> > performance hit. For this solution to work, it would be better to make
> > python stop creating .pyc files when run as root.
> > 
> > 2. Make a separate python-support (inspired from emacsen-support)
> > package that takes care of the byte-compilation. This is the solution
> > I've been working on the last weeks, but it isn't ready yet.
> 
> In my opinion, 1 is the better course. As you said, 2 is a lot of work.
> Since I'm not convinced bytecode is desirable in the general case, I
> don't think it's worth maintaining such a python-support rather than
> just not using bytecode.
> 
> I would be interested in seeing what you have so far.

As I had a few time tonight, I could make it look slightly better, but
it still needs some work.

I'm attaching what I have so far. The patch for dh_python still isn't
complete, but it won't be difficult to finish. The update-python-modules
script, which relies on adding /var/lib/python-support/python2.X to the
path using a .pth file, is more complete. It's still missing support for
partial and complete rebuilds of its .pyc database, so that new python
versions can be installed, but it's also easy to do.

I'll also need some complicity from the python packages to handle this
properly. Namely, the python2.X packages will have to call the script -
if it exists - in their postinst and postrm, so that the installation of
a new python version triggers the compilation of the modules for that
new version. Matthias, would you allow this change?

Regards,
-- 
 .''`.           Josselin Mouette        /\./\
: :' :           josselin.mouette@ens-lyon.org
`. `'                        joss@debian.org
  `-  Debian GNU/Linux -- The power of freedom
--- /usr/bin/dh_python	2005-06-13 17:26:36.000000000 +0200
+++ dh_python	2006-01-02 00:02:48.000000000 +0100
@@ -44,9 +44,6 @@
 /usr/lib/$PACKAGE, /usr/share/$PACKAGE, /usr/lib/games/$PACKAGE,
 /usr/share/games/$PACKAGE and /usr/lib/python?.?/site-packages.
 
-Note: only /usr/lib/site-python, /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
@@ -122,10 +119,10 @@
 	delsubstvar($package, "python:Depends");
 
 	my @dirs = ("usr/lib/site-python", "usr/lib/$package", "usr/share/$package", "usr/lib/games/$package", "usr/share/games/$package", @ARGV );
-	my @dirs_so = ("usr/lib/site-python", @ARGV );
 
 	my $dep_on_python = 0;
 	my $strong_dep = 0;
+	my $dep_on_py_support = 0;
 	my $look_for_pythonXY = 1;
 
 	# First, the case of python-foo and pythonX.Y-foo
@@ -140,12 +137,10 @@
 	}
 	if ($package !~ /^python[0-9].[0-9]-/) {
 		push @dirs, "usr/lib/$usepython/site-packages";
-		push @dirs_so, "usr/lib/$usepython/site-packages";
 		$look_for_pythonXY = 0;
 	}
 
 	@dirs = grep -d, map "$tmp/$_", @dirs;
-	@dirs_so = grep -d, map "$tmp/$_", @dirs_so;
 
 	my $deps = 0;
 	my %verdeps = ();
@@ -170,18 +165,32 @@
 
 	# Look for python modules
 	my $dirlist="";
+	my $gen_dirlist="";
 	if (@dirs) {
 		foreach my $curdir (@dirs) {
 			my $has_module = 0;
+			my $has_bin_module = 0;
 			$curdir =~ s%^$tmp/%%;
 			find sub {
 				return unless -f;
 				if (/\.py$/) {
 					$has_module = 1;
 					doit(("rm","-f",$_."c",$_."o"));
+				} elif (/\.so$/) {
+					$has_bin_module = 1;
 				}
 			}, "$tmp/$curdir" ;
-			if ($has_module) {
+			if ($has_module && $has_bin_module == 0) {
+				$dep_on_py_support = 1;
+				if ($curdir eq "usr/lib/$usepython/site-packages") {
+					doit(("mkdir","-p","$tmp/usr/share"));
+					doit(("mv","-T",$curdir,"$tmp/usr/share/site-python"));
+					# pass the -s option to update-python-modules
+					$gen_dirlist="$gen_dirlist -s";
+				} else {
+					$gen_dirlist="$gen_dirlist /$curdir";
+				}
+			} elif ($has_module) {  # We have both kinds of modules
 				if ($dh{V_FLAG_SET}) {
 					$verdeps{$usepython} |= PY_MODULE_NONSTANDARD;
 				} else {
@@ -189,17 +198,7 @@
 				}
 				$dirlist="$dirlist /$curdir";
 			}
-		}
-	}
-	if (@dirs_so) {
-		foreach my $curdir (@dirs_so) {
-			my $has_module = 0;
-			$curdir =~ s%^$tmp/%%;
-			find sub {
-				return unless -f;
-				$has_module = 1 if /\.so$/;
-			}, "$tmp/$curdir" ;
-			if ($has_module) {
+			if ($has_bin_module) {
 				if ($dh{V_FLAG_SET}) {
 					$verdeps{$usepython} |= SO_MODULE_NONSTANDARD;
 				}
@@ -212,7 +211,7 @@
 
 	# Dependencies on current python
 	$dep_on_python = 1 if $deps;
-	$strong_dep = 1 if($deps & (PY_MODULE|SO_MODULE));
+	$strong_dep = 1 if($deps & SO_MODULE);
 
 	if ($dep_on_python) {
 		addsubstvar($package, "python:Depends", $python, ">= $python_version");
@@ -225,6 +224,14 @@
 
 	my $need_prerm = 0;
 
+	if ($dep_on_py_support) {
+		addsubstvar($package, "python:Depends", "python-support");
+# STOP HERE
+# - postinst work still has to be done
+autoscript($package,"postinst","postinst-python","s%#PYVER#%$pyver%;s%#DIRLIST#%$pydir%");
+		need_prerm = 1;
+	}
+
 	# Look for specific pythonX.Y modules
 	foreach my $pyver (@python_allversions) {
 		my $pydir="/usr/lib/$pyver/site-packages";
#! /usr/bin/python

import sys,os,os.path
from optparse import OptionParser
from py_compile import compile

#TODO : an option to check for existing python versions and remove/rebuild if
#necessary

basepath='/var/lib/python-support'

parser = OptionParser(usage="usage: %prog [options] directory [directory ...]")

parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
                  help="verbose output", default=False)
parser.add_option("-i", "--install", action="store_true", dest="inst_mode",
                  help="installation mode; compiled modules are made available for all python versions",
		  default=False)
parser.add_option("-b", "--bytecompile", action="store_false", dest="inst_mode",
                  help="byte-compilation mode; modules are only compiled, for the default python version [default]")
parser.add_option("-c", "--clean", action="store_true", dest="clean_mode",
		  help="clean modules instead of compiling them",
		  default=False)

(options, args) = parser.parse_args()

py_versions = ['2.1','2.2','2.3','2.4']
py_installed = [ 'python'+ver for ver in py_versions if os.path.exists('/usr/bin/python'+ver) ]

def debug(x):
  if(options.verbose):
    print x

def bytecompile_only(basedir,dir,file):
  if file.endswith('.py'):
    fullpath=os.path.join(basedir,dir,file)
    debug("compile "+fullpath+'c')
    compile(fullpath)

def clean_simple(basedir,dir,file):
  if file.endswith('.py'):
    fullpath=os.path.join(basedir,dir,file+'c')
    if os.path.exists(fullpath):
      debug("remove "+fullpath)
      os.remove(fullpath)

def compile_allversions(basedir,dir,file):
  fullpath=os.path.join(basedir,dir,file)
  for py in py_installed:
    destpath=os.path.join(basepath,py,dir,file)
    try:
      os.makedirs(os.path.join(basepath,py,dir))
    except OSError:
      pass
    if file.endswith('.py'):
      destpath+='c'
      debug("compile "+destpath)
      if py == "python"+sys.version[:3]:
        compile(fullpath,destpath)
      else:
      # D'uh, this one stinks, but it's the only way for non-default
      # versions
        command = 'import py_compile; py_compile.compile("%s","%s")'%(fullpath,destpath)
        os.spawnl(os.P_WAIT, '/usr/bin/'+py, py, '-c', command)
    elif not file.endswith('.pyc'):
      debug("link "+destpath)
      if os.path.exists(destpath):
        os.remove(destpath)
      os.symlink(fullpath,destpath)

def clean_allversions(basedir,dir,file):
  fullpath=os.path.join(basedir,dir,file)
  for py in py_installed:
    destpath=os.path.join(basepath,py,dir,file)
    if file.endswith('.py'):
      destpath+='c'
    if os.path.exists(destpath):
      debug("remove "+destpath)
      os.remove(destpath)
      try:
        os.removedirs(os.path.join(basepath,py,dir))
      except OSError:
        pass

if options.inst_mode:
  if options.clean_mode:
    action = clean_allversions
  else:
    action = compile_allversions
else:
  if options.clean_mode:
    action = clean_simple
  else:
    action = bytecompile_only

for basedir in args:
  debug("Looking at %s..."%(basedir))
  for dir, dirs, files in os.walk(basedir):
    dir = dir[len(basedir):].lstrip('/')
    for file in files:
      action(basedir, dir, file)

Attachment: signature.asc
Description: Ceci est une partie de message =?ISO-8859-1?Q?num=E9riquement?= =?ISO-8859-1?Q?_sign=E9e?=


Reply to: