home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 April / PCWorld_2001-04_cd.bin / Software / TemaCD / webclean / !!!python!!! / BeOpen-Python-2.0.exe / PATHFIX.PY < prev    next >
Encoding:
Python Source  |  2000-09-28  |  3.9 KB  |  150 lines

  1. #! /usr/bin/env python
  2.  
  3. # Change the #! line occurring in Python scripts.  The new interpreter
  4. # pathname must be given with a -i option.
  5. #
  6. # Command line arguments are files or directories to be processed.
  7. # Directories are searched recursively for files whose name looks
  8. # like a python module.
  9. # Symbolic links are always ignored (except as explicit directory
  10. # arguments).  Of course, the original file is kept as a back-up
  11. # (with a "~" attached to its name).
  12. #
  13. # Undoubtedly you can do this using find and sed or perl, but this is
  14. # a nice example of Python code that recurses down a directory tree
  15. # and uses regular expressions.  Also note several subtleties like
  16. # preserving the file's mode and avoiding to even write a temp file
  17. # when no changes are needed for a file.
  18. #
  19. # NB: by changing only the function fixfile() you can turn this
  20. # into a program for a different change to Python programs...
  21.  
  22. import sys
  23. import regex
  24. import os
  25. from stat import *
  26. import string
  27. import getopt
  28.  
  29. err = sys.stderr.write
  30. dbg = err
  31. rep = sys.stdout.write
  32.  
  33. new_interpreter = None
  34.  
  35. def main():
  36.     global new_interpreter
  37.     usage = ('usage: %s -i /interpreter file-or-directory ...\n' %
  38.          sys.argv[0])
  39.     try:
  40.         opts, args = getopt.getopt(sys.argv[1:], 'i:')
  41.     except getopt.error, msg:
  42.         err(msg + '\n')
  43.         err(usage)
  44.         sys.exit(2)
  45.     for o, a in opts:
  46.         if o == '-i':
  47.             new_interpreter = a
  48.     if not new_interpreter or new_interpreter[0] != '/' or not args:
  49.         err('-i option or file-or-directory missing\n')
  50.         err(usage)
  51.         sys.exit(2)
  52.     bad = 0
  53.     for arg in args:
  54.         if os.path.isdir(arg):
  55.             if recursedown(arg): bad = 1
  56.         elif os.path.islink(arg):
  57.             err(arg + ': will not process symbolic links\n')
  58.             bad = 1
  59.         else:
  60.             if fix(arg): bad = 1
  61.     sys.exit(bad)
  62.  
  63. ispythonprog = regex.compile('^[a-zA-Z0-9_]+\.py$')
  64. def ispython(name):
  65.     return ispythonprog.match(name) >= 0
  66.  
  67. def recursedown(dirname):
  68.     dbg('recursedown(' + `dirname` + ')\n')
  69.     bad = 0
  70.     try:
  71.         names = os.listdir(dirname)
  72.     except os.error, msg:
  73.         err(dirname + ': cannot list directory: ' + `msg` + '\n')
  74.         return 1
  75.     names.sort()
  76.     subdirs = []
  77.     for name in names:
  78.         if name in (os.curdir, os.pardir): continue
  79.         fullname = os.path.join(dirname, name)
  80.         if os.path.islink(fullname): pass
  81.         elif os.path.isdir(fullname):
  82.             subdirs.append(fullname)
  83.         elif ispython(name):
  84.             if fix(fullname): bad = 1
  85.     for fullname in subdirs:
  86.         if recursedown(fullname): bad = 1
  87.     return bad
  88.  
  89. def fix(filename):
  90. ##    dbg('fix(' + `filename` + ')\n')
  91.     try:
  92.         f = open(filename, 'r')
  93.     except IOError, msg:
  94.         err(filename + ': cannot open: ' + `msg` + '\n')
  95.         return 1
  96.     line = f.readline()
  97.     fixed = fixline(line)
  98.     if line == fixed:
  99.         rep(filename+': no change\n')
  100.         f.close()
  101.         return
  102.     head, tail = os.path.split(filename)
  103.     tempname = os.path.join(head, '@' + tail)
  104.     try:
  105.         g = open(tempname, 'w')
  106.     except IOError, msg:
  107.         f.close()
  108.         err(tempname+': cannot create: '+`msg`+'\n')
  109.         return 1
  110.     rep(filename + ': updating\n')
  111.     g.write(fixed)
  112.     BUFSIZE = 8*1024
  113.     while 1:
  114.         buf = f.read(BUFSIZE)
  115.         if not buf: break
  116.         g.write(buf)
  117.     g.close()
  118.     f.close()
  119.  
  120.     # Finishing touch -- move files
  121.  
  122.     # First copy the file's mode to the temp file
  123.     try:
  124.         statbuf = os.stat(filename)
  125.         os.chmod(tempname, statbuf[ST_MODE] & 07777)
  126.     except os.error, msg:
  127.         err(tempname + ': warning: chmod failed (' + `msg` + ')\n')
  128.     # Then make a backup of the original file as filename~
  129.     try:
  130.         os.rename(filename, filename + '~')
  131.     except os.error, msg:
  132.         err(filename + ': warning: backup failed (' + `msg` + ')\n')
  133.     # Now move the temp file to the original file
  134.     try:
  135.         os.rename(tempname, filename)
  136.     except os.error, msg:
  137.         err(filename + ': rename failed (' + `msg` + ')\n')
  138.         return 1
  139.     # Return succes
  140.     return 0
  141.  
  142. def fixline(line):
  143.     if line[:2] != '#!':
  144.         return line
  145.     if string.find(line, "python") < 0:
  146.         return line
  147.     return '#! %s\n' % new_interpreter
  148.  
  149. main()
  150.