util.py revision ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1
12689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward"""distutils.util
22689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
32689e3ddce70e8acc5bc231a80221980d5bdfec3Greg WardGeneral-purpose utility functions used throughout the Distutils
42689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward(especially in command classes).  Mostly filesystem manipulation, but
52689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Wardnot limited to that.  The functions in this module generally raise
62689e3ddce70e8acc5bc231a80221980d5bdfec3Greg WardDistutilsFileError when they have problems with the filesystem, because
72689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Wardos.error in pre-1.5.2 Python only gives the error message and not the
82689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Wardfile causing it."""
92689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
102689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# created 1999/03/08, Greg Ward
112689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
122689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward__rcsid__ = "$Id$"
132689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
142689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Wardimport os
152689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Wardfrom distutils.errors import *
162689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
172689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
18ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward# cache for by mkpath() -- in addition to cheapening redundant calls,
19ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward# eliminates redundant "creating /foo/bar/baz" messages in dry-run mode
20ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg WardPATH_CREATED = {}
21ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward
222689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# I don't use os.makedirs because a) it's new to Python 1.5.2, and
232689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# b) it blows up if the directory already exists (I want to silently
242689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# succeed in that case).
25e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Warddef mkpath (name, mode=0777, verbose=0, dry_run=0):
262689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    """Create a directory and any missing ancestor directories.  If the
272689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       directory already exists, return silently.  Raise
282689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       DistutilsFileError if unable to create some directory along the
292689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       way (eg. some sub-path exists, but is a file rather than a
302689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       directory).  If 'verbose' is true, print a one-line summary of
312689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       each mkdir to stdout."""
322689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
33ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward    global PATH_CREATED
34ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward
352689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    # XXX what's the better way to handle verbosity? print as we create
362689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    # each directory in the path (the current behaviour), or only announce
37ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward    # the creation of the whole path? (quite easy to do the latter since
38ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward    # we're not using a recursive algorithm)
392689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
402689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    if os.path.isdir (name):
412689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        return
42ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward    if PATH_CREATED.get (name):
43ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward        return
442689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
452689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    (head, tail) = os.path.split (name)
462689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    tails = [tail]                      # stack of lone dirs to create
472689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
482689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    while head and tail and not os.path.isdir (head):
492689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        #print "splitting '%s': " % head,
502689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        (head, tail) = os.path.split (head)
512689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        #print "to ('%s','%s')" % (head, tail)
522689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        tails.insert (0, tail)          # push next higher dir onto stack
532689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
542689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    #print "stack of tails:", tails
552689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
56e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward    # now 'head' contains the deepest directory that already exists
57e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward    # (that is, the child of 'head' in 'name' is the highest directory
58e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward    # that does *not* exist)
592689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    for d in tails:
602689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        #print "head = %s, d = %s: " % (head, d),
612689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        head = os.path.join (head, d)
622689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        if verbose:
632689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            print "creating", head
64e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward
65e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward        if not dry_run:
66e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward            try:
67e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward                os.mkdir (head)
68e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward            except os.error, (errno, errstr):
69e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward                raise DistutilsFileError, "%s: %s" % (head, errstr)
702689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
71ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward        PATH_CREATED[head] = 1
72ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward
732689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# mkpath ()
742689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
752689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
76138ce653cc8ae53e500c480a9763ee92b9813439Greg Warddef newer (source, target):
77138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    """Return true if 'source' exists and is more recently modified than
78138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       'target', or if 'source' exists and 'target' doesn't.  Return
79138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       false if both exist and 'target' is the same age or younger than
80138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       'source'.  Raise DistutilsFileError if 'source' does not
81138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       exist."""
82138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
83138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if not os.path.exists (source):
84138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        raise DistutilsFileError, "file '%s' does not exist" % source
85138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if not os.path.exists (target):
862689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        return 1
872689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
88138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    from stat import ST_MTIME
89138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    mtime1 = os.stat(source)[ST_MTIME]
90138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    mtime2 = os.stat(target)[ST_MTIME]
912689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
922689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    return mtime1 > mtime2
932689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
942689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# newer ()
952689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
962689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
97138ce653cc8ae53e500c480a9763ee92b9813439Greg Warddef newer_pairwise (sources, targets):
98138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
99138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    """Walk two filename lists in parallel, testing if each 'target' is
100138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       up-to-date relative to its corresponding 'source'.  If so, both
101138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       are deleted from their respective lists.  Return a list of tuples
102138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       containing the deleted (source,target) pairs."""
103138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
104138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if len (sources) != len (targets):
105138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        raise ValueError, "'sources' and 'targets' must be same length"
106138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
107138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    goners = []
108138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    for i in range (len (sources)-1, -1, -1):
109138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        if not newer (sources[i], targets[i]):
110138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            goners.append ((sources[i], targets[i]))
111138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            del sources[i]
112138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            del targets[i]
113138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    goners.reverse()
114138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    return goners
115138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
116138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward# newer_pairwise ()
117138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
118138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
119138ce653cc8ae53e500c480a9763ee92b9813439Greg Warddef newer_group (sources, target):
120138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    """Return true if 'target' is out-of-date with respect to any
121138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       file listed in 'sources'.  In other words, if 'target' exists and
122138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       is newer than every file in 'sources', return false; otherwise
123138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       return true."""
124138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
125138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    # If the target doesn't even exist, then it's definitely out-of-date.
126138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if not os.path.exists (target):
127138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        return 1
128138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
129138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    # Otherwise we have to find out the hard way: if *any* source file
130138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    # is more recent than 'target', then 'target' is out-of-date and
131138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    # we can immediately return true.  If we fall through to the end
132138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    # of the loop, then 'target' is up-to-date and we return false.
133138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    from stat import ST_MTIME
134138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    target_mtime = os.stat (target)[ST_MTIME]
135138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    for source in sources:
136138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        source_mtime = os.stat(source)[ST_MTIME]
137138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        if source_mtime > target_mtime:
138138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            return 1
139138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    else:
140138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        return 0
141138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
142138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward# newer_group ()
143138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
144138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
1452689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Warddef make_file (src, dst, func, args,
1462689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward               verbose=0, update_message=None, noupdate_message=None):
1472689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    """Makes 'dst' from 'src' (both filenames) by calling 'func' with
1482689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       'args', but only if it needs to: i.e. if 'dst' does not exist or
1492689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       'src' is newer than 'dst'."""
1502689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
1512689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    if newer (src, dst):
1522689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        if verbose and update_message:
1532689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            print update_message
1542689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        apply (func, args)
1552689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    else:
1562689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        if verbose and noupdate_message:
1572689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            print noupdate_message
1582689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
1592689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# make_file ()
1602689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
1612689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
1622689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Warddef _copy_file_contents (src, dst, buffer_size=16*1024):
1632689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    """Copy the file 'src' to 'dst'; both must be filenames.  Any error
1642689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       opening either file, reading from 'src', or writing to 'dst',
1652689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       raises DistutilsFileError.  Data is read/written in chunks of
1662689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       'buffer_size' bytes (default 16k).  No attempt is made to handle
1672689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       anything apart from regular files."""
1682689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
1692689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    # Stolen from shutil module in the standard library, but with
1702689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    # custom error-handling added.
1712689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
1722689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    fsrc = None
1732689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    fdst = None
1742689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    try:
1752689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        try:
1762689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            fsrc = open(src, 'rb')
1772689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        except os.error, (errno, errstr):
1782689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            raise DistutilsFileError, "could not open %s: %s" % (src, errstr)
1792689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
1802689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        try:
1812689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            fdst = open(dst, 'wb')
1822689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        except os.error, (errno, errstr):
1832689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            raise DistutilsFileError, "could not create %s: %s" % (dst, errstr)
1842689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
1852689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        while 1:
1862689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            try:
1872689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward                buf = fsrc.read (buffer_size)
1882689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            except os.error, (errno, errstr):
1892689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward                raise DistutilsFileError, \
1902689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward                      "could not read from %s: %s" % (src, errstr)
1912689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
1922689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            if not buf:
1932689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward                break
1942689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
1952689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            try:
1962689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward                fdst.write(buf)
1972689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            except os.error, (errno, errstr):
1982689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward                raise DistutilsFileError, \
1992689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward                      "could not write to %s: %s" % (dst, errstr)
2002689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2012689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    finally:
2022689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        if fdst:
2032689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            fdst.close()
2042689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        if fsrc:
2052689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            fsrc.close()
2062689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2072689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# _copy_file_contents()
2082689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2092689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2102689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Warddef copy_file (src, dst,
2112689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward               preserve_mode=1,
2122689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward               preserve_times=1,
2132689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward               update=0,
214e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward               verbose=0,
215e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward               dry_run=0):
2162689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2172689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    """Copy a file 'src' to 'dst'.  If 'dst' is a directory, then 'src'
2182689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       is copied there with the same name; otherwise, it must be a
2192689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       filename.  (If the file exists, it will be ruthlessly clobbered.)
2202689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       If 'preserve_mode' is true (the default), the file's mode (type
2212689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       and permission bits, or whatever is analogous on the current
2222689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       platform) is copied.  If 'preserve_times' is true (the default),
2232689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       the last-modified and last-access times are copied as well.  If
2242689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       'update' is true, 'src' will only be copied if 'dst' does not
2252689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       exist, or if 'dst' does exist but is older than 'src'.  If
2262689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       'verbose' is true, then a one-line summary of the copy will be
227884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward       printed to stdout.
228884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward
229884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward       Return true if the file was copied (or would have been copied),
230884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward       false otherwise (ie. 'update' was true and the destination is
231884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward       up-to-date)."""
2322689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2332689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    # XXX doesn't copy Mac-specific metadata
2342689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2352689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    from stat import *
2362689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2372689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    if not os.path.isfile (src):
2382689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        raise DistutilsFileError, \
239138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward              "can't copy %s: not a regular file" % src
2402689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2412689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    if os.path.isdir (dst):
2422689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        dir = dst
2432689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        dst = os.path.join (dst, os.path.basename (src))
2442689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    else:
2452689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        dir = os.path.dirname (dst)
2462689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2472689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    if update and not newer (src, dst):
248884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward        if verbose:
249884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward            print "not copying %s (output up-to-date)" % src
250884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward        return 0
2512689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2522689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    if verbose:
2532689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        print "copying %s -> %s" % (src, dir)
2542689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
255e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward    if dry_run:
256884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward        return 1
257e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward
258e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward    _copy_file_contents (src, dst)
2592689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    if preserve_mode or preserve_times:
2602689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        st = os.stat (src)
2615116f90ece5586cdca04e91cf0b1bb566bcc258dGreg Ward
2625116f90ece5586cdca04e91cf0b1bb566bcc258dGreg Ward        # According to David Ascher <da@ski.org>, utime() should be done
2635116f90ece5586cdca04e91cf0b1bb566bcc258dGreg Ward        # before chmod() (at least under NT).
2642689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        if preserve_times:
2652689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            os.utime (dst, (st[ST_ATIME], st[ST_MTIME]))
2665116f90ece5586cdca04e91cf0b1bb566bcc258dGreg Ward        if preserve_mode:
2675116f90ece5586cdca04e91cf0b1bb566bcc258dGreg Ward            os.chmod (dst, S_IMODE (st[ST_MODE]))
2682689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
269884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward    return 1
270884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward
2712689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# copy_file ()
2722689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2732689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2742689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Warddef copy_tree (src, dst,
2752689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward               preserve_mode=1,
2762689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward               preserve_times=1,
2772689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward               preserve_symlinks=0,
2782689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward               update=0,
279e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward               verbose=0,
280e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward               dry_run=0):
281e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward
2822689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2832689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    """Copy an entire directory tree 'src' to a new location 'dst'.  Both
2842689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       'src' and 'dst' must be directory names.  If 'src' is not a
2852689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       directory, raise DistutilsFileError.  If 'dst' does not exist, it
286884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward       is created with 'mkpath'.  The end result of the copy is that
2872689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       every file in 'src' is copied to 'dst', and directories under
288884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward       'src' are recursively copied to 'dst'.  Return the list of files
289884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward       copied (under their output names) -- note that if 'update' is true,
290884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward       this might be less than the list of files considered.  Return
291884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward       value is not affected by 'dry_run'.
2922689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
2932689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       'preserve_mode' and 'preserve_times' are the same as for
2942689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       'copy_file'; note that they only apply to regular files, not to
2952689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       directories.  If 'preserve_symlinks' is true, symlinks will be
2962689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       copied as symlinks (on platforms that support them!); otherwise
2972689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       (the default), the destination of the symlink will be copied.
2982689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward       'update' and 'verbose' are the same as for 'copy_file'."""
2992689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
300138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if not dry_run and not os.path.isdir (src):
3012689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        raise DistutilsFileError, \
3022689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward              "cannot copy tree %s: not a directory" % src
3032689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    try:
3042689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        names = os.listdir (src)
3052689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    except os.error, (errno, errstr):
306138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        if dry_run:
307138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            names = []
308138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        else:
309138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            raise DistutilsFileError, \
310138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward                  "error listing files in %s: %s" % (src, errstr)
3112689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
312e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward    if not dry_run:
313e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward        mkpath (dst, verbose=verbose)
3142689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
315884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward    outputs = []
316884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward
3172689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward    for n in names:
3182689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        src_name = os.path.join (src, n)
3192689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        dst_name = os.path.join (dst, n)
3202689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
3212689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        if preserve_symlinks and os.path.islink (src_name):
3222689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward            link_dest = os.readlink (src_name)
323e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward            if verbose:
324e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward                print "linking %s -> %s" % (dst_name, link_dest)
325e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward            if not dry_run:
326e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward                os.symlink (link_dest, dst_name)
327884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward            outputs.append (dst_name)
328884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward
3292689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        elif os.path.isdir (src_name):
330884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward            outputs[-1:] = \
331884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward                copy_tree (src_name, dst_name,
332884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward                           preserve_mode, preserve_times, preserve_symlinks,
333884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward                           update, verbose, dry_run)
3342689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward        else:
335884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward            if (copy_file (src_name, dst_name,
336884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward                           preserve_mode, preserve_times,
337884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward                           update, verbose, dry_run)):
338884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward                outputs.append (dst_name)
339884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward
340884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward    return outputs
3412689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
3422689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# copy_tree ()
343138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
344138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
345138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward# XXX I suspect this is Unix-specific -- need porting help!
346138ce653cc8ae53e500c480a9763ee92b9813439Greg Warddef move_file (src, dst,
347138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward               verbose=0,
348138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward               dry_run=0):
349138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
350138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    """Move a file 'src' to 'dst'.  If 'dst' is a directory, the file
351138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       will be moved into it with the same name; otherwise, 'src' is
352138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       just renamed to 'dst'.  Return the new full name of the file.
353138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
354138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       Handles cross-device moves on Unix using
355138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward       'copy_file()'.  What about other systems???"""
356138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
357138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    from os.path import exists, isfile, isdir, basename, dirname
358138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
359138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if verbose:
360138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        print "moving %s -> %s" % (src, dst)
361138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
362138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if dry_run:
363138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        return dst
364138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
365138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if not isfile (src):
366138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        raise DistutilsFileError, \
367138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward              "can't move '%s': not a regular file" % src
368138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
369138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if isdir (dst):
370138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        dst = os.path.join (dst, basename (src))
371138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    elif exists (dst):
372138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        raise DistutilsFileError, \
373138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward              "can't move '%s': destination '%s' already exists" % \
374138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward              (src, dst)
375138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
376138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if not isdir (dirname (dst)):
377138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        raise DistutilsFileError, \
378138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward              "can't move '%s': destination '%s' not a valid path" % \
379138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward              (src, dst)
380138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
381138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    copy_it = 0
382138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    try:
383138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        os.rename (src, dst)
384138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    except os.error, (num, msg):
385138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        if num == errno.EXDEV:
386138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            copy_it = 1
387138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        else:
388138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            raise DistutilsFileError, \
389138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward                  "couldn't move '%s' to '%s': %s" % (src, dst, msg)
390138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
391138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    if copy_it:
392138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        copy_file (src, dst)
393138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        try:
394138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            os.unlink (src)
395138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward        except os.error, (num, msg):
396138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            try:
397138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward                os.unlink (dst)
398138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            except os.error:
399138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward                pass
400138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward            raise DistutilsFileError, \
401138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward                  ("couldn't move '%s' to '%s' by copy/delete: " +
402138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward                   "delete '%s' failed: %s") % \
403138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward                  (src, dst, src, msg)
404138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
405138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward    return dst
406138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward
407138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward# move_file ()
408ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward
409ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward
410ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Warddef write_file (filename, contents):
411ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward    """Create a file with the specified naem and write 'contents' (a
412ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward       sequence of strings without line terminators) to it."""
413ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward
414ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward    f = open (filename, "w")
415ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward    for line in contents:
416ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward        f.write (line + "\n")
417ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward    f.close ()
418