PyXR

c:\python24\lib \ distutils \ file_util.py



0001 """distutils.file_util
0002 
0003 Utility functions for operating on single files.
0004 """
0005 
0006 # This module should be kept compatible with Python 1.5.2.
0007 
0008 __revision__ = "$Id: file_util.py,v 1.16 2004/07/18 06:14:42 tim_one Exp $"
0009 
0010 import os
0011 from distutils.errors import DistutilsFileError
0012 from distutils import log
0013 
0014 # for generating verbose output in 'copy_file()'
0015 _copy_action = { None:   'copying',
0016                  'hard': 'hard linking',
0017                  'sym':  'symbolically linking' }
0018 
0019 
0020 def _copy_file_contents (src, dst, buffer_size=16*1024):
0021     """Copy the file 'src' to 'dst'; both must be filenames.  Any error
0022     opening either file, reading from 'src', or writing to 'dst', raises
0023     DistutilsFileError.  Data is read/written in chunks of 'buffer_size'
0024     bytes (default 16k).  No attempt is made to handle anything apart from
0025     regular files.
0026     """
0027     # Stolen from shutil module in the standard library, but with
0028     # custom error-handling added.
0029 
0030     fsrc = None
0031     fdst = None
0032     try:
0033         try:
0034             fsrc = open(src, 'rb')
0035         except os.error, (errno, errstr):
0036             raise DistutilsFileError, \
0037                   "could not open '%s': %s" % (src, errstr)
0038 
0039         if os.path.exists(dst):
0040             try:
0041                 os.unlink(dst)
0042             except os.error, (errno, errstr):
0043                 raise DistutilsFileError, \
0044                       "could not delete '%s': %s" % (dst, errstr)
0045 
0046         try:
0047             fdst = open(dst, 'wb')
0048         except os.error, (errno, errstr):
0049             raise DistutilsFileError, \
0050                   "could not create '%s': %s" % (dst, errstr)
0051 
0052         while 1:
0053             try:
0054                 buf = fsrc.read(buffer_size)
0055             except os.error, (errno, errstr):
0056                 raise DistutilsFileError, \
0057                       "could not read from '%s': %s" % (src, errstr)
0058 
0059             if not buf:
0060                 break
0061 
0062             try:
0063                 fdst.write(buf)
0064             except os.error, (errno, errstr):
0065                 raise DistutilsFileError, \
0066                       "could not write to '%s': %s" % (dst, errstr)
0067 
0068     finally:
0069         if fdst:
0070             fdst.close()
0071         if fsrc:
0072             fsrc.close()
0073 
0074 # _copy_file_contents()
0075 
0076 def copy_file (src, dst,
0077                preserve_mode=1,
0078                preserve_times=1,
0079                update=0,
0080                link=None,
0081                verbose=0,
0082                dry_run=0):
0083 
0084     """Copy a file 'src' to 'dst'.  If 'dst' is a directory, then 'src' is
0085     copied there with the same name; otherwise, it must be a filename.  (If
0086     the file exists, it will be ruthlessly clobbered.)  If 'preserve_mode'
0087     is true (the default), the file's mode (type and permission bits, or
0088     whatever is analogous on the current platform) is copied.  If
0089     'preserve_times' is true (the default), the last-modified and
0090     last-access times are copied as well.  If 'update' is true, 'src' will
0091     only be copied if 'dst' does not exist, or if 'dst' does exist but is
0092     older than 'src'.
0093 
0094     'link' allows you to make hard links (os.link) or symbolic links
0095     (os.symlink) instead of copying: set it to "hard" or "sym"; if it is
0096     None (the default), files are copied.  Don't set 'link' on systems that
0097     don't support it: 'copy_file()' doesn't check if hard or symbolic
0098     linking is available.
0099 
0100     Under Mac OS, uses the native file copy function in macostools; on
0101     other systems, uses '_copy_file_contents()' to copy file contents.
0102 
0103     Return a tuple (dest_name, copied): 'dest_name' is the actual name of
0104     the output file, and 'copied' is true if the file was copied (or would
0105     have been copied, if 'dry_run' true).
0106     """
0107     # XXX if the destination file already exists, we clobber it if
0108     # copying, but blow up if linking.  Hmmm.  And I don't know what
0109     # macostools.copyfile() does.  Should definitely be consistent, and
0110     # should probably blow up if destination exists and we would be
0111     # changing it (ie. it's not already a hard/soft link to src OR
0112     # (not update) and (src newer than dst).
0113 
0114     from distutils.dep_util import newer
0115     from stat import ST_ATIME, ST_MTIME, ST_MODE, S_IMODE
0116 
0117     if not os.path.isfile(src):
0118         raise DistutilsFileError, \
0119               "can't copy '%s': doesn't exist or not a regular file" % src
0120 
0121     if os.path.isdir(dst):
0122         dir = dst
0123         dst = os.path.join(dst, os.path.basename(src))
0124     else:
0125         dir = os.path.dirname(dst)
0126 
0127     if update and not newer(src, dst):
0128         log.debug("not copying %s (output up-to-date)", src)
0129         return dst, 0
0130 
0131     try:
0132         action = _copy_action[link]
0133     except KeyError:
0134         raise ValueError, \
0135               "invalid value '%s' for 'link' argument" % link
0136     if os.path.basename(dst) == os.path.basename(src):
0137         log.info("%s %s -> %s", action, src, dir)
0138     else:
0139         log.info("%s %s -> %s", action, src, dst)
0140 
0141     if dry_run:
0142         return (dst, 1)
0143 
0144     # On Mac OS, use the native file copy routine
0145     if os.name == 'mac':
0146         import macostools
0147         try:
0148             macostools.copy(src, dst, 0, preserve_times)
0149         except os.error, exc:
0150             raise DistutilsFileError, \
0151                   "could not copy '%s' to '%s': %s" % (src, dst, exc[-1])
0152 
0153     # If linking (hard or symbolic), use the appropriate system call
0154     # (Unix only, of course, but that's the caller's responsibility)
0155     elif link == 'hard':
0156         if not (os.path.exists(dst) and os.path.samefile(src, dst)):
0157             os.link(src, dst)
0158     elif link == 'sym':
0159         if not (os.path.exists(dst) and os.path.samefile(src, dst)):
0160             os.symlink(src, dst)
0161 
0162     # Otherwise (non-Mac, not linking), copy the file contents and
0163     # (optionally) copy the times and mode.
0164     else:
0165         _copy_file_contents(src, dst)
0166         if preserve_mode or preserve_times:
0167             st = os.stat(src)
0168 
0169             # According to David Ascher <da@ski.org>, utime() should be done
0170             # before chmod() (at least under NT).
0171             if preserve_times:
0172                 os.utime(dst, (st[ST_ATIME], st[ST_MTIME]))
0173             if preserve_mode:
0174                 os.chmod(dst, S_IMODE(st[ST_MODE]))
0175 
0176     return (dst, 1)
0177 
0178 # copy_file ()
0179 
0180 
0181 # XXX I suspect this is Unix-specific -- need porting help!
0182 def move_file (src, dst,
0183                verbose=0,
0184                dry_run=0):
0185 
0186     """Move a file 'src' to 'dst'.  If 'dst' is a directory, the file will
0187     be moved into it with the same name; otherwise, 'src' is just renamed
0188     to 'dst'.  Return the new full name of the file.
0189 
0190     Handles cross-device moves on Unix using 'copy_file()'.  What about
0191     other systems???
0192     """
0193     from os.path import exists, isfile, isdir, basename, dirname
0194     import errno
0195 
0196     log.info("moving %s -> %s", src, dst)
0197 
0198     if dry_run:
0199         return dst
0200 
0201     if not isfile(src):
0202         raise DistutilsFileError, \
0203               "can't move '%s': not a regular file" % src
0204 
0205     if isdir(dst):
0206         dst = os.path.join(dst, basename(src))
0207     elif exists(dst):
0208         raise DistutilsFileError, \
0209               "can't move '%s': destination '%s' already exists" % \
0210               (src, dst)
0211 
0212     if not isdir(dirname(dst)):
0213         raise DistutilsFileError, \
0214               "can't move '%s': destination '%s' not a valid path" % \
0215               (src, dst)
0216 
0217     copy_it = 0
0218     try:
0219         os.rename(src, dst)
0220     except os.error, (num, msg):
0221         if num == errno.EXDEV:
0222             copy_it = 1
0223         else:
0224             raise DistutilsFileError, \
0225                   "couldn't move '%s' to '%s': %s" % (src, dst, msg)
0226 
0227     if copy_it:
0228         copy_file(src, dst)
0229         try:
0230             os.unlink(src)
0231         except os.error, (num, msg):
0232             try:
0233                 os.unlink(dst)
0234             except os.error:
0235                 pass
0236             raise DistutilsFileError, \
0237                   ("couldn't move '%s' to '%s' by copy/delete: " +
0238                    "delete '%s' failed: %s") % \
0239                   (src, dst, src, msg)
0240 
0241     return dst
0242 
0243 # move_file ()
0244 
0245 
0246 def write_file (filename, contents):
0247     """Create a file with the specified name and write 'contents' (a
0248     sequence of strings without line terminators) to it.
0249     """
0250     f = open(filename, "w")
0251     for line in contents:
0252         f.write(line + "\n")
0253     f.close()
0254 

Generated by PyXR 0.9.4
SourceForge.net Logo