home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 June / PCWorld_2005-06_cd.bin / software / vyzkuste / firewally / firewally.exe / framework-2.3.exe / dir_util.py < prev    next >
Text File  |  2003-12-30  |  8KB  |  229 lines

  1. """distutils.dir_util
  2.  
  3. Utility functions for manipulating directories and directory trees."""
  4.  
  5. # This module should be kept compatible with Python 1.5.2.
  6.  
  7. __revision__ = "$Id: dir_util.py,v 1.12 2002/11/26 17:42:48 akuchling Exp $"
  8.  
  9. import os, sys
  10. from types import *
  11. from distutils.errors import DistutilsFileError, DistutilsInternalError
  12. from distutils import log
  13.  
  14. # cache for by mkpath() -- in addition to cheapening redundant calls,
  15. # eliminates redundant "creating /foo/bar/baz" messages in dry-run mode
  16. _path_created = {}
  17.  
  18. # I don't use os.makedirs because a) it's new to Python 1.5.2, and
  19. # b) it blows up if the directory already exists (I want to silently
  20. # succeed in that case).
  21. def mkpath (name, mode=0777, verbose=0, dry_run=0):
  22.     """Create a directory and any missing ancestor directories.  If the
  23.        directory already exists (or if 'name' is the empty string, which
  24.        means the current directory, which of course exists), then do
  25.        nothing.  Raise DistutilsFileError if unable to create some
  26.        directory along the way (eg. some sub-path exists, but is a file
  27.        rather than a directory).  If 'verbose' is true, print a one-line
  28.        summary of each mkdir to stdout.  Return the list of directories
  29.        actually created."""
  30.  
  31.     global _path_created
  32.  
  33.     # Detect a common bug -- name is None
  34.     if type(name) is not StringType:
  35.         raise DistutilsInternalError, \
  36.               "mkpath: 'name' must be a string (got %s)" % `name`
  37.  
  38.     # XXX what's the better way to handle verbosity? print as we create
  39.     # each directory in the path (the current behaviour), or only announce
  40.     # the creation of the whole path? (quite easy to do the latter since
  41.     # we're not using a recursive algorithm)
  42.  
  43.     name = os.path.normpath(name)
  44.     created_dirs = []
  45.     if os.path.isdir(name) or name == '':
  46.         return created_dirs
  47.     if _path_created.get(os.path.abspath(name)):
  48.         return created_dirs
  49.  
  50.     (head, tail) = os.path.split(name)
  51.     tails = [tail]                      # stack of lone dirs to create
  52.  
  53.     while head and tail and not os.path.isdir(head):
  54.         #print "splitting '%s': " % head,
  55.         (head, tail) = os.path.split(head)
  56.         #print "to ('%s','%s')" % (head, tail)
  57.         tails.insert(0, tail)          # push next higher dir onto stack
  58.  
  59.     #print "stack of tails:", tails
  60.  
  61.     # now 'head' contains the deepest directory that already exists
  62.     # (that is, the child of 'head' in 'name' is the highest directory
  63.     # that does *not* exist)
  64.     for d in tails:
  65.         #print "head = %s, d = %s: " % (head, d),
  66.         head = os.path.join(head, d)
  67.         abs_head = os.path.abspath(head)
  68.  
  69.         if _path_created.get(abs_head):
  70.             continue
  71.  
  72.         log.info("creating %s", head)
  73.  
  74.         if not dry_run:
  75.             try:
  76.                 os.mkdir(head)
  77.                 created_dirs.append(head)
  78.             except OSError, exc:
  79.                 raise DistutilsFileError, \
  80.                       "could not create '%s': %s" % (head, exc[-1])
  81.  
  82.         _path_created[abs_head] = 1
  83.     return created_dirs
  84.  
  85. # mkpath ()
  86.  
  87.  
  88. def create_tree (base_dir, files, mode=0777, verbose=0, dry_run=0):
  89.  
  90.     """Create all the empty directories under 'base_dir' needed to
  91.        put 'files' there.  'base_dir' is just the a name of a directory
  92.        which doesn't necessarily exist yet; 'files' is a list of filenames
  93.        to be interpreted relative to 'base_dir'.  'base_dir' + the
  94.        directory portion of every file in 'files' will be created if it
  95.        doesn't already exist.  'mode', 'verbose' and 'dry_run' flags are as
  96.        for 'mkpath()'."""
  97.  
  98.     # First get the list of directories to create
  99.     need_dir = {}
  100.     for file in files:
  101.         need_dir[os.path.join(base_dir, os.path.dirname(file))] = 1
  102.     need_dirs = need_dir.keys()
  103.     need_dirs.sort()
  104.  
  105.     # Now create them
  106.     for dir in need_dirs:
  107.         mkpath(dir, mode, dry_run=dry_run)
  108.  
  109. # create_tree ()
  110.  
  111.  
  112. def copy_tree (src, dst,
  113.                preserve_mode=1,
  114.                preserve_times=1,
  115.                preserve_symlinks=0,
  116.                update=0,
  117.                verbose=0,
  118.                dry_run=0):
  119.  
  120.     """Copy an entire directory tree 'src' to a new location 'dst'.  Both
  121.        'src' and 'dst' must be directory names.  If 'src' is not a
  122.        directory, raise DistutilsFileError.  If 'dst' does not exist, it is
  123.        created with 'mkpath()'.  The end result of the copy is that every
  124.        file in 'src' is copied to 'dst', and directories under 'src' are
  125.        recursively copied to 'dst'.  Return the list of files that were
  126.        copied or might have been copied, using their output name.  The
  127.        return value is unaffected by 'update' or 'dry_run': it is simply
  128.        the list of all files under 'src', with the names changed to be
  129.        under 'dst'.
  130.  
  131.        'preserve_mode' and 'preserve_times' are the same as for
  132.        'copy_file'; note that they only apply to regular files, not to
  133.        directories.  If 'preserve_symlinks' is true, symlinks will be
  134.        copied as symlinks (on platforms that support them!); otherwise
  135.        (the default), the destination of the symlink will be copied.
  136.        'update' and 'verbose' are the same as for 'copy_file'."""
  137.  
  138.     from distutils.file_util import copy_file
  139.  
  140.     if not dry_run and not os.path.isdir(src):
  141.         raise DistutilsFileError, \
  142.               "cannot copy tree '%s': not a directory" % src
  143.     try:
  144.         names = os.listdir(src)
  145.     except os.error, (errno, errstr):
  146.         if dry_run:
  147.             names = []
  148.         else:
  149.             raise DistutilsFileError, \
  150.                   "error listing files in '%s': %s" % (src, errstr)
  151.  
  152.     if not dry_run:
  153.         mkpath(dst)
  154.  
  155.     outputs = []
  156.  
  157.     for n in names:
  158.         src_name = os.path.join(src, n)
  159.         dst_name = os.path.join(dst, n)
  160.  
  161.         if preserve_symlinks and os.path.islink(src_name):
  162.             link_dest = os.readlink(src_name)
  163.             log.info("linking %s -> %s", dst_name, link_dest)
  164.             if not dry_run:
  165.                 os.symlink(link_dest, dst_name)
  166.             outputs.append(dst_name)
  167.  
  168.         elif os.path.isdir(src_name):
  169.             outputs.extend(
  170.                 copy_tree(src_name, dst_name, preserve_mode,
  171.                           preserve_times, preserve_symlinks, update,
  172.                           dry_run=dry_run))
  173.         else:
  174.             copy_file(src_name, dst_name, preserve_mode,
  175.                       preserve_times, update, dry_run=dry_run)
  176.             outputs.append(dst_name)
  177.  
  178.     return outputs
  179.  
  180. # copy_tree ()
  181.  
  182. # Helper for remove_tree()
  183. def _build_cmdtuple(path, cmdtuples):
  184.     for f in os.listdir(path):
  185.         real_f = os.path.join(path,f)
  186.         if os.path.isdir(real_f) and not os.path.islink(real_f):
  187.             _build_cmdtuple(real_f, cmdtuples)
  188.         else:
  189.             cmdtuples.append((os.remove, real_f))
  190.     cmdtuples.append((os.rmdir, path))
  191.  
  192.  
  193. def remove_tree (directory, verbose=0, dry_run=0):
  194.     """Recursively remove an entire directory tree.  Any errors are ignored
  195.     (apart from being reported to stdout if 'verbose' is true).
  196.     """
  197.     from distutils.util import grok_environment_error
  198.     global _path_created
  199.  
  200.     log.info("removing '%s' (and everything under it)", directory)
  201.     if dry_run:
  202.         return
  203.     cmdtuples = []
  204.     _build_cmdtuple(directory, cmdtuples)
  205.     for cmd in cmdtuples:
  206.         try:
  207.             apply(cmd[0], (cmd[1],))
  208.             # remove dir from cache if it's already there
  209.             abspath = os.path.abspath(cmd[1])
  210.             if _path_created.has_key(abspath):
  211.                 del _path_created[abspath]
  212.         except (IOError, OSError), exc:
  213.             log.warn(grok_environment_error(
  214.                     exc, "error removing %s: " % directory))
  215.  
  216.  
  217. def ensure_relative (path):
  218.     """Take the full path 'path', and make it a relative path so
  219.     it can be the second argument to os.path.join().
  220.     """
  221.     drive, path = os.path.splitdrive(path)
  222.     if sys.platform == 'mac':
  223.         return os.sep + path
  224.     else:
  225.         if path[0:1] == os.sep:
  226.             path = drive + path[1:]
  227.         return path
  228.  
  229.