util.py revision 3ce77fd05ed00168f618b63401d770ccc4f04b09
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 123ce77fd05ed00168f618b63401d770ccc4f04b09Greg Ward__revision__ = "$Id$" 132689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 14585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Wardimport os, string 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 40f3b997a7f0040c6eeade614cc1b1e003d3e31818Greg Ward name = os.path.normpath (name) 41f3b997a7f0040c6eeade614cc1b1e003d3e31818Greg Ward 422689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward if os.path.isdir (name): 432689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward return 44ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward if PATH_CREATED.get (name): 45ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward return 462689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 472689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward (head, tail) = os.path.split (name) 482689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward tails = [tail] # stack of lone dirs to create 492689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 502689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward while head and tail and not os.path.isdir (head): 512689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward #print "splitting '%s': " % head, 522689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward (head, tail) = os.path.split (head) 532689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward #print "to ('%s','%s')" % (head, tail) 542689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward tails.insert (0, tail) # push next higher dir onto stack 552689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 562689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward #print "stack of tails:", tails 572689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 58e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward # now 'head' contains the deepest directory that already exists 59e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward # (that is, the child of 'head' in 'name' is the highest directory 60e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward # that does *not* exist) 612689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward for d in tails: 622689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward #print "head = %s, d = %s: " % (head, d), 632689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward head = os.path.join (head, d) 64cd1486fff14888437837298ada405b13ce965217Greg Ward if PATH_CREATED.get (head): 65cd1486fff14888437837298ada405b13ce965217Greg Ward continue 66cd1486fff14888437837298ada405b13ce965217Greg Ward 672689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward if verbose: 682689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward print "creating", head 69e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward 70e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward if not dry_run: 71e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward try: 72e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward os.mkdir (head) 73e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward except os.error, (errno, errstr): 74e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward raise DistutilsFileError, "%s: %s" % (head, errstr) 752689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 76ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward PATH_CREATED[head] = 1 77ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward 782689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# mkpath () 792689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 802689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 81138ce653cc8ae53e500c480a9763ee92b9813439Greg Warddef newer (source, target): 82138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward """Return true if 'source' exists and is more recently modified than 83138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 'target', or if 'source' exists and 'target' doesn't. Return 84138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward false if both exist and 'target' is the same age or younger than 85138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 'source'. Raise DistutilsFileError if 'source' does not 86138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward exist.""" 87138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 88138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward if not os.path.exists (source): 89138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward raise DistutilsFileError, "file '%s' does not exist" % source 90138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward if not os.path.exists (target): 912689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward return 1 922689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 93138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward from stat import ST_MTIME 94138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward mtime1 = os.stat(source)[ST_MTIME] 95138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward mtime2 = os.stat(target)[ST_MTIME] 962689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 972689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward return mtime1 > mtime2 982689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 992689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# newer () 1002689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 1012689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 102138ce653cc8ae53e500c480a9763ee92b9813439Greg Warddef newer_pairwise (sources, targets): 103138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward """Walk two filename lists in parallel, testing if each 'target' is 104138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward up-to-date relative to its corresponding 'source'. If so, both 105138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward are deleted from their respective lists. Return a list of tuples 106138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward containing the deleted (source,target) pairs.""" 107138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 108138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward if len (sources) != len (targets): 109138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward raise ValueError, "'sources' and 'targets' must be same length" 110138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 111138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward goners = [] 112138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward for i in range (len (sources)-1, -1, -1): 113138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward if not newer (sources[i], targets[i]): 114138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward goners.append ((sources[i], targets[i])) 115138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward del sources[i] 116138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward del targets[i] 117138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward goners.reverse() 118138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward return goners 119138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 120138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward# newer_pairwise () 121138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 122138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 1237b7679eb79a7ad7766881b05fab0681850f79a6fGreg Warddef newer_group (sources, target, missing='error'): 124138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward """Return true if 'target' is out-of-date with respect to any 125138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward file listed in 'sources'. In other words, if 'target' exists and 126138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward is newer than every file in 'sources', return false; otherwise 1277b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward return true. 'missing' controls what we do when a source file is 1287b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward missing; the default ("error") is to blow up with an OSError from 1297b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward inside 'stat()'; if it is "ignore", we silently drop any missing 1307b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward source files; if it is "newer", any missing source files make us 1317b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward assume that 'target' is out-of-date (this is handy in "dry-run" 1327b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward mode: it'll make you pretend to carry out commands that wouldn't 1337b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward work because inputs are missing, but that doesn't matter because 1347b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward you're not actually going to run the commands).""" 135138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 136138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward # If the target doesn't even exist, then it's definitely out-of-date. 137138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward if not os.path.exists (target): 138138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward return 1 139138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 140138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward # Otherwise we have to find out the hard way: if *any* source file 141138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward # is more recent than 'target', then 'target' is out-of-date and 142138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward # we can immediately return true. If we fall through to the end 143138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward # of the loop, then 'target' is up-to-date and we return false. 144138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward from stat import ST_MTIME 145138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward target_mtime = os.stat (target)[ST_MTIME] 146138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward for source in sources: 1477b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward if not os.path.exists (source): 1487b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward if missing == 'error': # blow up when we stat() the file 1497b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward pass 1507b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward elif missing == 'ignore': # missing source dropped from 1517b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward continue # target's dependency list 1527b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward elif missing == 'newer': # missing source means target is 1537b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward return 1 # out-of-date 1547b7679eb79a7ad7766881b05fab0681850f79a6fGreg Ward 155138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward source_mtime = os.stat(source)[ST_MTIME] 156138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward if source_mtime > target_mtime: 157138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward return 1 158138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward else: 159138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward return 0 160138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 161138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward# newer_group () 162138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 163138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 164f3b997a7f0040c6eeade614cc1b1e003d3e31818Greg Ward# XXX this isn't used anywhere, and worse, it has the same name as a method 165f3b997a7f0040c6eeade614cc1b1e003d3e31818Greg Ward# in Command with subtly different semantics. (This one just has one 166f3b997a7f0040c6eeade614cc1b1e003d3e31818Greg Ward# source -> one dest; that one has many sources -> one dest.) Nuke it? 1672689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Warddef make_file (src, dst, func, args, 1682689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward verbose=0, update_message=None, noupdate_message=None): 1692689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward """Makes 'dst' from 'src' (both filenames) by calling 'func' with 1702689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 'args', but only if it needs to: i.e. if 'dst' does not exist or 1712689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 'src' is newer than 'dst'.""" 1722689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 1732689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward if newer (src, dst): 1742689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward if verbose and update_message: 1752689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward print update_message 1762689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward apply (func, args) 1772689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward else: 1782689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward if verbose and noupdate_message: 1792689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward print noupdate_message 1802689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 1812689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# make_file () 1822689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 1832689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 1842689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Warddef _copy_file_contents (src, dst, buffer_size=16*1024): 1852689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward """Copy the file 'src' to 'dst'; both must be filenames. Any error 1862689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward opening either file, reading from 'src', or writing to 'dst', 1872689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward raises DistutilsFileError. Data is read/written in chunks of 1882689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 'buffer_size' bytes (default 16k). No attempt is made to handle 1892689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward anything apart from regular files.""" 1902689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 1912689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward # Stolen from shutil module in the standard library, but with 1922689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward # custom error-handling added. 1932689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 1942689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward fsrc = None 1952689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward fdst = None 1962689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward try: 1972689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward try: 1982689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward fsrc = open(src, 'rb') 1992689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward except os.error, (errno, errstr): 2002689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward raise DistutilsFileError, "could not open %s: %s" % (src, errstr) 2012689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 2022689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward try: 2032689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward fdst = open(dst, 'wb') 2042689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward except os.error, (errno, errstr): 2052689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward raise DistutilsFileError, "could not create %s: %s" % (dst, errstr) 2062689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 2072689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward while 1: 2082689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward try: 2092689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward buf = fsrc.read (buffer_size) 2102689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward except os.error, (errno, errstr): 2112689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward raise DistutilsFileError, \ 2122689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward "could not read from %s: %s" % (src, errstr) 2132689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 2142689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward if not buf: 2152689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward break 2162689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 2172689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward try: 2182689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward fdst.write(buf) 2192689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward except os.error, (errno, errstr): 2202689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward raise DistutilsFileError, \ 2212689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward "could not write to %s: %s" % (dst, errstr) 2222689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 2232689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward finally: 2242689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward if fdst: 2252689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward fdst.close() 2262689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward if fsrc: 2272689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward fsrc.close() 2282689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 2292689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# _copy_file_contents() 2302689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 2312689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 2322689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Warddef copy_file (src, dst, 2332689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward preserve_mode=1, 2342689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward preserve_times=1, 2352689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward update=0, 236e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward verbose=0, 237e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward dry_run=0): 2382689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 2392689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward """Copy a file 'src' to 'dst'. If 'dst' is a directory, then 'src' 2402689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward is copied there with the same name; otherwise, it must be a 2412689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward filename. (If the file exists, it will be ruthlessly clobbered.) 2422689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward If 'preserve_mode' is true (the default), the file's mode (type 2432689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward and permission bits, or whatever is analogous on the current 2442689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward platform) is copied. If 'preserve_times' is true (the default), 2452689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward the last-modified and last-access times are copied as well. If 2462689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 'update' is true, 'src' will only be copied if 'dst' does not 2472689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward exist, or if 'dst' does exist but is older than 'src'. If 2482689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 'verbose' is true, then a one-line summary of the copy will be 249884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward printed to stdout. 250884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward 251884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward Return true if the file was copied (or would have been copied), 252884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward false otherwise (ie. 'update' was true and the destination is 253884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward up-to-date).""" 2542689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 2552689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward # XXX doesn't copy Mac-specific metadata 2562689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 2572689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward from stat import * 2582689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 2592689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward if not os.path.isfile (src): 2602689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward raise DistutilsFileError, \ 261138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward "can't copy %s: not a regular file" % src 2622689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 2632689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward if os.path.isdir (dst): 2642689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward dir = dst 2652689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward dst = os.path.join (dst, os.path.basename (src)) 2662689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward else: 2672689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward dir = os.path.dirname (dst) 2682689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 2692689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward if update and not newer (src, dst): 270884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward if verbose: 271884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward print "not copying %s (output up-to-date)" % src 272884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward return 0 2732689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 2742689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward if verbose: 2752689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward print "copying %s -> %s" % (src, dir) 2762689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 277e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward if dry_run: 278884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward return 1 279e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward 280e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward _copy_file_contents (src, dst) 2812689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward if preserve_mode or preserve_times: 2822689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward st = os.stat (src) 2835116f90ece5586cdca04e91cf0b1bb566bcc258dGreg Ward 2845116f90ece5586cdca04e91cf0b1bb566bcc258dGreg Ward # According to David Ascher <da@ski.org>, utime() should be done 2855116f90ece5586cdca04e91cf0b1bb566bcc258dGreg Ward # before chmod() (at least under NT). 2862689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward if preserve_times: 2872689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward os.utime (dst, (st[ST_ATIME], st[ST_MTIME])) 2885116f90ece5586cdca04e91cf0b1bb566bcc258dGreg Ward if preserve_mode: 2895116f90ece5586cdca04e91cf0b1bb566bcc258dGreg Ward os.chmod (dst, S_IMODE (st[ST_MODE])) 2902689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 291884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward return 1 292884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward 2932689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# copy_file () 2942689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 2952689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 2962689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Warddef copy_tree (src, dst, 2972689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward preserve_mode=1, 2982689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward preserve_times=1, 2992689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward preserve_symlinks=0, 3002689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward update=0, 301e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward verbose=0, 302e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward dry_run=0): 303e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward 3042689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 3052689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward """Copy an entire directory tree 'src' to a new location 'dst'. Both 3062689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 'src' and 'dst' must be directory names. If 'src' is not a 3072689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward directory, raise DistutilsFileError. If 'dst' does not exist, it 308f3b997a7f0040c6eeade614cc1b1e003d3e31818Greg Ward is created with 'mkpath()'. The end result of the copy is that 3092689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward every file in 'src' is copied to 'dst', and directories under 310884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward 'src' are recursively copied to 'dst'. Return the list of files 311884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward copied (under their output names) -- note that if 'update' is true, 312884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward this might be less than the list of files considered. Return 313884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward value is not affected by 'dry_run'. 3142689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 3152689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 'preserve_mode' and 'preserve_times' are the same as for 3162689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 'copy_file'; note that they only apply to regular files, not to 3172689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward directories. If 'preserve_symlinks' is true, symlinks will be 3182689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward copied as symlinks (on platforms that support them!); otherwise 3192689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward (the default), the destination of the symlink will be copied. 3202689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 'update' and 'verbose' are the same as for 'copy_file'.""" 3212689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 322138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward if not dry_run and not os.path.isdir (src): 3232689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward raise DistutilsFileError, \ 3242689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward "cannot copy tree %s: not a directory" % src 3252689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward try: 3262689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward names = os.listdir (src) 3272689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward except os.error, (errno, errstr): 328138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward if dry_run: 329138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward names = [] 330138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward else: 331138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward raise DistutilsFileError, \ 332138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward "error listing files in %s: %s" % (src, errstr) 3332689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 334e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward if not dry_run: 335e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward mkpath (dst, verbose=verbose) 3362689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 337884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward outputs = [] 338884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward 3392689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward for n in names: 3402689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward src_name = os.path.join (src, n) 3412689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward dst_name = os.path.join (dst, n) 3422689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 3432689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward if preserve_symlinks and os.path.islink (src_name): 3442689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward link_dest = os.readlink (src_name) 345e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward if verbose: 346e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward print "linking %s -> %s" % (dst_name, link_dest) 347e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward if not dry_run: 348e765a3bb61073c4a08acb863e2c897aa2c5bb1dbGreg Ward os.symlink (link_dest, dst_name) 349884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward outputs.append (dst_name) 350884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward 3512689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward elif os.path.isdir (src_name): 352a002edc85b25160cfffe610df9ab7337efc8f0c0Greg Ward outputs.extend ( 353884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward copy_tree (src_name, dst_name, 354884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward preserve_mode, preserve_times, preserve_symlinks, 355a002edc85b25160cfffe610df9ab7337efc8f0c0Greg Ward update, verbose, dry_run)) 3562689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward else: 357884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward if (copy_file (src_name, dst_name, 358884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward preserve_mode, preserve_times, 359884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward update, verbose, dry_run)): 360884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward outputs.append (dst_name) 361884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward 362884df454b271cf8f433d36aa0613cf1c62288c8eGreg Ward return outputs 3632689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward 3642689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# copy_tree () 365138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 366138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 367138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward# XXX I suspect this is Unix-specific -- need porting help! 368138ce653cc8ae53e500c480a9763ee92b9813439Greg Warddef move_file (src, dst, 369138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward verbose=0, 370138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward dry_run=0): 371138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 372138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward """Move a file 'src' to 'dst'. If 'dst' is a directory, the file 373138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward will be moved into it with the same name; otherwise, 'src' is 374138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward just renamed to 'dst'. Return the new full name of the file. 375138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 376138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward Handles cross-device moves on Unix using 377138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 'copy_file()'. What about other systems???""" 378138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 379138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward from os.path import exists, isfile, isdir, basename, dirname 380138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 381138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward if verbose: 382138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward print "moving %s -> %s" % (src, dst) 383138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 384138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward if dry_run: 385138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward return dst 386138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 387138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward if not isfile (src): 388138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward raise DistutilsFileError, \ 389138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward "can't move '%s': not a regular file" % src 390138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 391138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward if isdir (dst): 392138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward dst = os.path.join (dst, basename (src)) 393138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward elif exists (dst): 394138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward raise DistutilsFileError, \ 395138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward "can't move '%s': destination '%s' already exists" % \ 396138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward (src, dst) 397138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 398138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward if not isdir (dirname (dst)): 399138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward raise DistutilsFileError, \ 400138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward "can't move '%s': destination '%s' not a valid path" % \ 401138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward (src, dst) 402138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 403138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward copy_it = 0 404138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward try: 405138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward os.rename (src, dst) 406138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward except os.error, (num, msg): 407138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward if num == errno.EXDEV: 408138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward copy_it = 1 409138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward else: 410138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward raise DistutilsFileError, \ 411138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward "couldn't move '%s' to '%s': %s" % (src, dst, msg) 412138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 413138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward if copy_it: 414138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward copy_file (src, dst) 415138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward try: 416138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward os.unlink (src) 417138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward except os.error, (num, msg): 418138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward try: 419138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward os.unlink (dst) 420138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward except os.error: 421138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward pass 422138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward raise DistutilsFileError, \ 423138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward ("couldn't move '%s' to '%s' by copy/delete: " + 424138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward "delete '%s' failed: %s") % \ 425138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward (src, dst, src, msg) 426138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 427138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward return dst 428138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward 429138ce653cc8ae53e500c480a9763ee92b9813439Greg Ward# move_file () 430ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward 431ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward 432ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Warddef write_file (filename, contents): 433f3b997a7f0040c6eeade614cc1b1e003d3e31818Greg Ward """Create a file with the specified name and write 'contents' (a 434ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward sequence of strings without line terminators) to it.""" 435ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward 436ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward f = open (filename, "w") 437ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward for line in contents: 438ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward f.write (line + "\n") 439ac1424a9ceb07cbd249c67e40bb1bf4ac38e8df1Greg Ward f.close () 440585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward 441585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward 442585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Warddef get_platform (): 443585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward """Return a string (suitable for tacking onto directory names) that 444585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward identifies the current platform. Under Unix, identifies both the OS 445585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward and hardware architecture, e.g. "linux-i586", "solaris-sparc", 446585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward "irix-mips". For Windows and Mac OS, just returns 'sys.platform' -- 447585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward i.e. "???" or "???".""" 448585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward 449585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward if os.name == 'posix': 450585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward uname = os.uname() 451585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward OS = uname[0] 452585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward arch = uname[4] 453585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward return "%s-%s" % (string.lower (OS), string.lower (arch)) 454585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward else: 455585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward return sys.platform 456585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward 457585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Ward# get_platform() 458