home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / sbin / update-python-modules < prev    next >
Encoding:
Text File  |  2006-08-08  |  10.2 KB  |  316 lines

  1. #! /usr/bin/python
  2. #
  3. # copyright (c) 2006 Josselin Mouette <joss@debian.org>
  4. # Licensed under the GNU Lesser General Public License, version 2.1
  5. # See COPYING for details
  6.  
  7. import sys,os,os.path
  8. from optparse import OptionParser
  9. from py_compile import compile
  10.  
  11. basepath='/var/lib/python-support'
  12. sourcepath='/usr/share/python-support'
  13. extensionpath='/usr/lib/python-support'
  14.  
  15. parser = OptionParser(usage="usage: %prog [options] [directory [...]]")
  16.  
  17. parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
  18.                   help="verbose output", default=False)
  19. parser.add_option("-b", "--bytecompile", action="store_false", dest="inst_mode",
  20.                   help="byte-compilation mode; modules are only compiled, for the default python version [default]")
  21. parser.add_option("-i", "--install", action="store_true", dest="inst_mode",
  22.                   help="installation mode; compiled modules are made available for all python versions",
  23.           default=False)
  24. parser.add_option("-c", "--clean", action="store_true", dest="clean_mode",
  25.           help="clean modules instead of compiling them",
  26.           default=False)
  27. parser.add_option("-a", "--rebuild-all", action="store_true",
  28.                   dest="rebuild_all", default=False,
  29.           help="rebuild all modules for a new default python version")
  30. parser.add_option("-f", "--force-rebuild-all", action="store_true",
  31.                   dest="rebuild_everything", default=False,
  32.           help="rebuild all modules, including installed modules for all python versions.")
  33.  
  34. (options, args) = parser.parse_args()
  35.  
  36. if not os.path.isdir(basepath):
  37.   os.mkdir(basepath)
  38.  
  39. sys.path.append("/usr/lib/python-support/private/")
  40. import pysupport
  41. from pysupport import py_supported,py_installed,py_oldversions
  42.  
  43. def debug(x):
  44.   if(options.verbose):
  45.     print x
  46.  
  47. # I should use the sets type instead
  48. def isect(l1,l2):
  49.   return [i for i in l1 if i in l2]
  50.   
  51. def concat(l1,l2):
  52.   return l1 + [i for i in l2 if i not in l1]
  53.  
  54. versions_dict={}
  55.  
  56. def dir_versions(dir):
  57.   if dir not in versions_dict:
  58.     verfile=os.path.join(dir,'.version')
  59.     if dir.startswith(extensionpath):
  60.       # Directory in /usr/lib: only one version
  61.       vers=os.path.split(dir)[1]
  62.       if vers in py_supported:
  63.         versions_dict[dir]=[vers]
  64.       else:
  65.         versions_dict[dir]=[]
  66.     elif dir.startswith(sourcepath):
  67.       # Directory in /usr/share
  68.       extdir=dir.replace(sourcepath,extensionpath,1)
  69.       if os.path.exists(verfile):
  70.         # If we have a .version, use it
  71.         versions_dict[dir]=pysupport.version_list(file(verfile).readline())
  72.       elif os.path.isdir(extdir):
  73.         # Try to obtain the list of supported versions
  74.         # from the extensions in /usr/lib
  75.         versions_dict[dir]=isect(py_supported,os.listdir(extdir))
  76.       else:
  77.         # Otherwise, support all versions
  78.         versions_dict[dir]=py_supported
  79.     else:
  80.       raise "Internal error. This is a bug in python-support."
  81.   return versions_dict[dir]
  82.  
  83. def bytecompile_only(basedir,dir,file):
  84.   if file.endswith('.py'):
  85.     fullpath=os.path.join(basedir,dir,file)
  86.     debug("compile "+fullpath+'c')
  87.     compile(fullpath)
  88.  
  89. def clean_simple(basedir,dir,file):
  90.   if file.endswith('.py'):
  91.     for ext in ['c','o']:
  92.       fullpath=os.path.join(basedir,dir,file+ext)
  93.       if os.path.exists(fullpath):
  94.         debug("remove "+fullpath)
  95.         os.remove(fullpath)
  96.  
  97. def install_modules(versions):
  98.   def install_modules_func(basedir,dir,file):
  99.     if file == '.version':
  100.       return
  101.     fullpath=os.path.join(basedir,dir,file)
  102.     for py in isect(dir_versions(basedir),versions):
  103.       destpath=os.path.join(basepath,py,dir,file)
  104.       try:
  105.         os.makedirs(os.path.join(basepath,py,dir))
  106.       except OSError:
  107.         pass
  108.       if file[-4:] not in ['.pyc','.pyo']:
  109.         debug("link "+destpath)
  110.         if os.path.exists(destpath):
  111.           # Oops, the file already exists. 
  112.           # Check whether we are conflicting with something else.
  113.           for otherdir in dirs_i:
  114.             if otherdir == basedir:
  115.               continue
  116.             if os.path.exists(os.path.join(otherdir,dir,file)):
  117.               raise "Trying to overwrite %s which is already provided by %s"%(os.path.join(dir,file),otherdir)
  118.           # This is probably a case of postinst re-running. 
  119.           # Let's proceed.
  120.           debug("overwrite! "+destpath)
  121.           os.remove(destpath)
  122.         os.symlink(fullpath,destpath)
  123.       # Files are NOT byte-compiled here, this MUST be done later.
  124.   return install_modules_func
  125.  
  126. def clean_modules(basedir,dir,file):
  127.   fullpath=os.path.join(basedir,dir,file)
  128.   for py in dir_versions(basedir):
  129.     destpath=os.path.join(basepath,py,dir,file)
  130.     l=[destpath]
  131.     if file.endswith('.py'):
  132.       l+=[destpath+'c',destpath+'o']
  133.     for path in l:
  134.       if os.path.exists(path):
  135.         debug("remove "+path)
  136.         os.remove(path)
  137.     try:
  138.       os.removedirs(os.path.join(basepath,py,dir))
  139.     except OSError:
  140.       pass
  141.  
  142. def clean_modules_gen(versions):
  143.   return clean_modules
  144.  
  145. def process(basedir,func):
  146.   debug("Looking at %s..."%(basedir))
  147.   for dir, dirs, files in os.walk(basedir):
  148.     dir = dir[len(basedir):].lstrip('/')
  149.     for file in files:
  150.       func(basedir, dir, file)
  151.  
  152. def process_extensions(basedir,func,version=None):
  153.   basedir=basedir.replace(sourcepath,extensionpath,1)
  154.   if os.path.isdir(basedir):
  155.     for vers in os.listdir(basedir):
  156.       if version and vers != version:
  157.         continue
  158.       verdir=os.path.join(basedir,vers)
  159.       if os.path.isdir(verdir):
  160.         process(verdir,func([vers]))
  161.  
  162. def dirlist_file(f):
  163.   return [ l.rstrip('\n') for l in file(f) if len(l)>1 ]
  164.  
  165. def generate_pathfile(py):
  166.   path=os.path.join(basepath,py)
  167.   if not os.path.isdir(path):
  168.     return
  169.   pathfile=os.path.join(path,".path")
  170.   debug("Generation of %s..."%pathfile)
  171.   pathlist=[path]
  172.   for f in os.listdir(path):
  173.     f=os.path.join(path,f)
  174.     if f.endswith(".pth") and os.path.isfile(f):
  175.       for l in file(f):
  176.         l=l.rstrip('\n')
  177.         pathlist.append(l)
  178.         pathlist.append(os.path.join(path,l))
  179.   fd=file(pathfile,"w")
  180.   fd.writelines([l+'\n' for l in pathlist])
  181.  
  182. def bytecompile_all(py,path=None):
  183.   if not path:
  184.     path=os.path.join(basepath,py)
  185.     generate_pathfile(py)
  186.   if not os.path.isdir(path):
  187.     return
  188.   debug("Byte-compilation of whole %s..."%path)
  189.   os.spawnl(os.P_WAIT, '/usr/bin/'+py, py,
  190.             os.path.join('/usr/lib/',py,'compileall.py'), '-q', path)
  191.  
  192. def bytecompile_privatedir(basedir):
  193.   versionfile=os.path.join(basedir,".pyversion")
  194.   if os.path.isfile(versionfile):
  195.     specific_version=file(versionfile).readline().rstrip('\n')
  196.     bytecompile_all("python"+specific_version,basedir)
  197.   else:
  198.     process(basedir,bytecompile_only)
  199.  
  200. # Read list from the source directory
  201. # directories are stuff to be installed
  202. # foo.dirs files list directories to bytecompile in place
  203. dirs_b = []
  204. dirs_i = []
  205. for f in os.listdir(sourcepath):
  206.   f=os.path.join(sourcepath,f)
  207.   if os.path.isdir(f):
  208.     dirs_i.append(f)
  209.   elif f.endswith('.dirs'):
  210.     dirs_b+=dirlist_file(f)
  211.  
  212. # Compatibility with python-support 0.1
  213. file_b_old = os.path.join(basepath,"bytecompiled")
  214. try:
  215.   dirs_b_old = []
  216.   for l in file(file_b_old):
  217.     l=l.rstrip('\n')
  218.     if l not in dirs_b:
  219.       dirs_b_old.append(l)
  220. except IOError:
  221.   pass
  222.  
  223. if options.rebuild_everything:
  224.   options.rebuild_all = True
  225.   for pyver in py_supported:
  226.     dir = os.path.join(basepath,pyver)
  227.     if os.path.isdir(dir):
  228.       os.spawnlp(os.P_WAIT, 'rm', 'rm', '-rf', dir)
  229.  
  230. # Check for changes in installed python versions
  231. for pyver in py_oldversions+py_supported:
  232.   dir = os.path.join(basepath,pyver)
  233.   if pyver in py_installed and not os.path.isdir(dir):
  234.     debug("Building all modules in %s..."%(dir))
  235.     for basedir in dirs_i:
  236.       process(basedir,install_modules([pyver]))
  237.       process_extensions(basedir,install_modules,pyver)
  238.     # Byte-compile after running install_modules
  239.     bytecompile_all(pyver)
  240.   if pyver not in py_installed and os.path.isdir(dir):
  241.     debug("Removing obsolete directory %s..."%(dir))
  242.     os.spawnlp(os.P_WAIT, 'rm', 'rm', '-rf', dir)
  243.   # Fix upgrade path from before the .path
  244.   if pyver in py_installed and not os.path.isfile(os.path.join(dir,".path")):
  245.     generate_pathfile(pyver)
  246.  
  247. if options.rebuild_all:
  248.   for basedir in dirs_b+dirs_b_old:
  249.     process(basedir,clean_simple)
  250.     bytecompile_privatedir(basedir)
  251.  
  252. do_dirs=[]
  253. for arg in args:
  254.   if not os.path.isabs(arg):
  255.     arg=os.path.join(sourcepath,arg)
  256.   if not os.path.exists(arg):
  257.     raise "%s does not exist"%arg
  258.   if not arg.startswith(sourcepath):
  259.     if options.inst_mode:
  260.       raise "%s is not in the python-support directory."%arg
  261.     else:
  262.       print """Warning: compatibility mode. Please put the directories in
  263. /usr/share/python-support/PACKAGE.dirs instead."""
  264.   if arg.endswith('.dirs'):
  265.     do_dirs+=dirlist_file(arg)
  266.   elif os.path.isdir(arg):
  267.     do_dirs.append(arg)
  268.   else:
  269.     raise "%s is not a directory"%arg
  270.  
  271. to_bytecompile=to_clean=[]
  272. for basedir in do_dirs:
  273.   if options.inst_mode:
  274.     if options.clean_mode:
  275.       process(basedir,clean_modules)
  276.       process_extensions(basedir,clean_modules_gen)
  277.       to_clean = concat(to_clean,isect(dir_versions(basedir),py_installed))
  278.     else:
  279.       process(basedir,install_modules(py_installed))
  280.       process_extensions(basedir,install_modules)
  281.       to_bytecompile = concat(to_bytecompile,isect(dir_versions(basedir),py_installed))
  282.   else:
  283.     if options.clean_mode:
  284.       process(basedir,clean_simple)
  285.       if basedir in dirs_b_old:
  286.         dirs_b_old.remove(basedir)
  287.     else:
  288.       bytecompile_privatedir(basedir)
  289.       if basedir not in dirs_b+dirs_b_old:
  290.         dirs_b_old.append(basedir)
  291. # Byte-compile after running install_modules
  292. for py in to_bytecompile:
  293.   bytecompile_all(py)
  294. # When removing a module, we have removed the .pyc but we still need
  295. # to regenerate the .path file
  296. for py in to_clean:
  297.   generate_pathfile(py)
  298.  
  299. # Compatibility and upgrade path from python-support 0.1
  300. if dirs_b_old:
  301.   print """Warning: the following directories containing private python 
  302. modules are not handled through a .dirs file. Please update
  303. the packages providing them."""
  304.   f=file(file_b_old,"w")
  305.   for dir in dirs_b_old:
  306.     print '  '+dir
  307.     f.write(dir+'\n')
  308.   f.close()
  309. elif os.path.exists(file_b_old):
  310.   os.remove(file_b_old)
  311.  
  312. # The "installed" file doesn't even need an upgrade path
  313. file_i=os.path.join(basepath,"installed")
  314. if os.path.exists(file_i):
  315.   os.remove(file_i)
  316.