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