home *** CD-ROM | disk | FTP | other *** search
/ H4CK3R 14 / hacker14.iso / programacao / pythonwin / python.exe / PATHFIX.PY < prev    next >
Encoding:
Python Source  |  2002-09-11  |  4.4 KB  |  149 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 getopt
  27.  
  28. err = sys.stderr.write
  29. dbg = err
  30. rep = sys.stdout.write
  31.  
  32. new_interpreter = None
  33.  
  34. def main():
  35.     global new_interpreter
  36.     usage = ('usage: %s -i /interpreter file-or-directory ...\n' %
  37.              sys.argv[0])
  38.     try:
  39.         opts, args = getopt.getopt(sys.argv[1:], 'i:')
  40.     except getopt.error, msg:
  41.         err(msg + '\n')
  42.         err(usage)
  43.         sys.exit(2)
  44.     for o, a in opts:
  45.         if o == '-i':
  46.             new_interpreter = a
  47.     if not new_interpreter or new_interpreter[0] != '/' or not args:
  48.         err('-i option or file-or-directory missing\n')
  49.         err(usage)
  50.         sys.exit(2)
  51.     bad = 0
  52.     for arg in args:
  53.         if os.path.isdir(arg):
  54.             if recursedown(arg): bad = 1
  55.         elif os.path.islink(arg):
  56.             err(arg + ': will not process symbolic links\n')
  57.             bad = 1
  58.         else:
  59.             if fix(arg): bad = 1
  60.     sys.exit(bad)
  61.  
  62. ispythonprog = regex.compile('^[a-zA-Z0-9_]+\.py$')
  63. def ispython(name):
  64.     return ispythonprog.match(name) >= 0
  65.  
  66. def recursedown(dirname):
  67.     dbg('recursedown(' + `dirname` + ')\n')
  68.     bad = 0
  69.     try:
  70.         names = os.listdir(dirname)
  71.     except os.error, msg:
  72.         err(dirname + ': cannot list directory: ' + `msg` + '\n')
  73.         return 1
  74.     names.sort()
  75.     subdirs = []
  76.     for name in names:
  77.         if name in (os.curdir, os.pardir): continue
  78.         fullname = os.path.join(dirname, name)
  79.         if os.path.islink(fullname): pass
  80.         elif os.path.isdir(fullname):
  81.             subdirs.append(fullname)
  82.         elif ispython(name):
  83.             if fix(fullname): bad = 1
  84.     for fullname in subdirs:
  85.         if recursedown(fullname): bad = 1
  86.     return bad
  87.  
  88. def fix(filename):
  89. ##  dbg('fix(' + `filename` + ')\n')
  90.     try:
  91.         f = open(filename, 'r')
  92.     except IOError, msg:
  93.         err(filename + ': cannot open: ' + `msg` + '\n')
  94.         return 1
  95.     line = f.readline()
  96.     fixed = fixline(line)
  97.     if line == fixed:
  98.         rep(filename+': no change\n')
  99.         f.close()
  100.         return
  101.     head, tail = os.path.split(filename)
  102.     tempname = os.path.join(head, '@' + tail)
  103.     try:
  104.         g = open(tempname, 'w')
  105.     except IOError, msg:
  106.         f.close()
  107.         err(tempname+': cannot create: '+`msg`+'\n')
  108.         return 1
  109.     rep(filename + ': updating\n')
  110.     g.write(fixed)
  111.     BUFSIZE = 8*1024
  112.     while 1:
  113.         buf = f.read(BUFSIZE)
  114.         if not buf: break
  115.         g.write(buf)
  116.     g.close()
  117.     f.close()
  118.  
  119.     # Finishing touch -- move files
  120.  
  121.     # First copy the file's mode to the temp file
  122.     try:
  123.         statbuf = os.stat(filename)
  124.         os.chmod(tempname, statbuf[ST_MODE] & 07777)
  125.     except os.error, msg:
  126.         err(tempname + ': warning: chmod failed (' + `msg` + ')\n')
  127.     # Then make a backup of the original file as filename~
  128.     try:
  129.         os.rename(filename, filename + '~')
  130.     except os.error, msg:
  131.         err(filename + ': warning: backup failed (' + `msg` + ')\n')
  132.     # Now move the temp file to the original file
  133.     try:
  134.         os.rename(tempname, filename)
  135.     except os.error, msg:
  136.         err(filename + ': rename failed (' + `msg` + ')\n')
  137.         return 1
  138.     # Return succes
  139.     return 0
  140.  
  141. def fixline(line):
  142.     if not line.startswith('#!'):
  143.         return line
  144.     if "python" not in line:
  145.         return line
  146.     return '#! %s\n' % new_interpreter
  147.  
  148. main()
  149.