| 
									
										
										
										
											2000-02-04 15:28:42 +00:00
										 |  |  | """Utility functions for copying files and directory trees.
 | 
					
						
							| 
									
										
										
										
											1997-04-29 14:45:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-08-18 20:03:17 +00:00
										 |  |  | XXX The functions here don't copy the resource fork or other metadata on Mac. | 
					
						
							| 
									
										
										
										
											1997-04-29 14:45:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | """
 | 
					
						
							| 
									
										
										
										
											1990-10-13 19:23:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1992-03-31 18:55:40 +00:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											1999-02-23 23:07:51 +00:00
										 |  |  | import sys | 
					
						
							| 
									
										
										
										
											1997-04-29 14:45:19 +00:00
										 |  |  | import stat | 
					
						
							| 
									
										
										
										
											2004-06-19 21:11:35 +00:00
										 |  |  | from os.path import abspath | 
					
						
							| 
									
										
										
										
											1990-10-13 19:23:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-02-15 22:15:14 +00:00
										 |  |  | __all__ = ["copyfileobj","copyfile","copymode","copystat","copy","copy2", | 
					
						
							| 
									
										
										
										
											2002-10-30 05:44:50 +00:00
										 |  |  |            "copytree","move","rmtree","Error"] | 
					
						
							| 
									
										
										
										
											2002-10-07 13:23:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-01 00:45:28 +00:00
										 |  |  | class Error(EnvironmentError): | 
					
						
							| 
									
										
										
										
											2002-10-07 13:23:24 +00:00
										 |  |  |     pass | 
					
						
							| 
									
										
										
										
											1990-10-13 19:23:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-12 09:55:30 +00:00
										 |  |  | def copyfileobj(fsrc, fdst, length=16*1024): | 
					
						
							|  |  |  |     """copy data from file-like object fsrc to file-like object fdst""" | 
					
						
							|  |  |  |     while 1: | 
					
						
							|  |  |  |         buf = fsrc.read(length) | 
					
						
							|  |  |  |         if not buf: | 
					
						
							|  |  |  |             break | 
					
						
							|  |  |  |         fdst.write(buf) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-08-14 13:30:02 +00:00
										 |  |  | def _samefile(src, dst): | 
					
						
							|  |  |  |     # Macintosh, Unix. | 
					
						
							|  |  |  |     if hasattr(os.path,'samefile'): | 
					
						
							| 
									
										
										
										
											2004-08-14 14:51:01 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             return os.path.samefile(src, dst) | 
					
						
							|  |  |  |         except OSError: | 
					
						
							|  |  |  |             return False | 
					
						
							| 
									
										
										
										
											2004-08-14 13:30:02 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # All other platforms: check for same pathname. | 
					
						
							|  |  |  |     return (os.path.normcase(os.path.abspath(src)) == | 
					
						
							|  |  |  |             os.path.normcase(os.path.abspath(dst))) | 
					
						
							| 
									
										
										
										
											2001-01-15 01:36:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1990-10-13 19:23:40 +00:00
										 |  |  | def copyfile(src, dst): | 
					
						
							| 
									
										
										
										
											1997-04-29 14:45:19 +00:00
										 |  |  |     """Copy data from src to dst""" | 
					
						
							| 
									
										
										
										
											2004-08-14 13:30:02 +00:00
										 |  |  |     if _samefile(src, dst): | 
					
						
							|  |  |  |         raise Error, "`%s` and `%s` are the same file" % (src, dst) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-04-29 14:06:46 +00:00
										 |  |  |     fsrc = None | 
					
						
							|  |  |  |     fdst = None | 
					
						
							|  |  |  |     try: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         fsrc = open(src, 'rb') | 
					
						
							|  |  |  |         fdst = open(dst, 'wb') | 
					
						
							| 
									
										
										
										
											2000-07-12 09:55:30 +00:00
										 |  |  |         copyfileobj(fsrc, fdst) | 
					
						
							| 
									
										
										
										
											1997-04-29 14:06:46 +00:00
										 |  |  |     finally: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         if fdst: | 
					
						
							|  |  |  |             fdst.close() | 
					
						
							|  |  |  |         if fsrc: | 
					
						
							|  |  |  |             fsrc.close() | 
					
						
							| 
									
										
										
										
											1990-10-13 19:23:40 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def copymode(src, dst): | 
					
						
							| 
									
										
										
										
											1997-04-29 14:45:19 +00:00
										 |  |  |     """Copy mode bits from src to dst""" | 
					
						
							| 
									
										
										
										
											2001-01-21 20:00:00 +00:00
										 |  |  |     if hasattr(os, 'chmod'): | 
					
						
							|  |  |  |         st = os.stat(src) | 
					
						
							| 
									
										
										
										
											2002-06-06 09:48:13 +00:00
										 |  |  |         mode = stat.S_IMODE(st.st_mode) | 
					
						
							| 
									
										
										
										
											2001-01-21 20:00:00 +00:00
										 |  |  |         os.chmod(dst, mode) | 
					
						
							| 
									
										
										
										
											1990-10-13 19:23:40 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def copystat(src, dst): | 
					
						
							| 
									
										
										
										
											2007-02-19 10:55:19 +00:00
										 |  |  |     """Copy all stat info (mode bits, atime, mtime, flags) from src to dst""" | 
					
						
							| 
									
										
										
										
											1997-04-29 14:06:46 +00:00
										 |  |  |     st = os.stat(src) | 
					
						
							| 
									
										
										
										
											2002-06-06 09:48:13 +00:00
										 |  |  |     mode = stat.S_IMODE(st.st_mode) | 
					
						
							| 
									
										
										
										
											2001-01-21 20:00:00 +00:00
										 |  |  |     if hasattr(os, 'utime'): | 
					
						
							| 
									
										
										
										
											2002-06-06 09:48:13 +00:00
										 |  |  |         os.utime(dst, (st.st_atime, st.st_mtime)) | 
					
						
							| 
									
										
										
										
											2001-01-21 20:00:00 +00:00
										 |  |  |     if hasattr(os, 'chmod'): | 
					
						
							|  |  |  |         os.chmod(dst, mode) | 
					
						
							| 
									
										
										
										
											2007-02-19 10:55:19 +00:00
										 |  |  |     if hasattr(os, 'chflags') and hasattr(st, 'st_flags'): | 
					
						
							|  |  |  |         os.chflags(dst, st.st_flags) | 
					
						
							| 
									
										
										
										
											1997-04-29 14:45:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1990-10-13 19:23:40 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def copy(src, dst): | 
					
						
							| 
									
										
										
										
											1997-04-29 14:45:19 +00:00
										 |  |  |     """Copy data and mode bits ("cp src dst").
 | 
					
						
							| 
									
										
										
										
											2001-01-15 01:36:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-04-29 14:45:19 +00:00
										 |  |  |     The destination may be a directory. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											1997-04-29 14:06:46 +00:00
										 |  |  |     if os.path.isdir(dst): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         dst = os.path.join(dst, os.path.basename(src)) | 
					
						
							| 
									
										
										
										
											1997-04-29 14:06:46 +00:00
										 |  |  |     copyfile(src, dst) | 
					
						
							|  |  |  |     copymode(src, dst) | 
					
						
							| 
									
										
										
										
											1990-10-13 19:23:40 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def copy2(src, dst): | 
					
						
							| 
									
										
										
										
											1997-04-29 14:45:19 +00:00
										 |  |  |     """Copy data and all stat info ("cp -p src dst").
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The destination may be a directory. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											1997-04-29 14:06:46 +00:00
										 |  |  |     if os.path.isdir(dst): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         dst = os.path.join(dst, os.path.basename(src)) | 
					
						
							| 
									
										
										
										
											1997-04-29 14:06:46 +00:00
										 |  |  |     copyfile(src, dst) | 
					
						
							|  |  |  |     copystat(src, dst) | 
					
						
							| 
									
										
										
										
											1990-10-13 19:23:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-04-29 14:45:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-23 21:36:32 +00:00
										 |  |  | def copytree(src, dst, symlinks=False): | 
					
						
							| 
									
										
										
										
											1997-04-29 14:45:19 +00:00
										 |  |  |     """Recursively copy a directory tree using copy2().
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The destination directory must not already exist. | 
					
						
							| 
									
										
										
										
											2003-02-23 21:36:32 +00:00
										 |  |  |     If exception(s) occur, an Error is raised with a list of reasons. | 
					
						
							| 
									
										
										
										
											1997-04-29 14:45:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     If the optional symlinks flag is true, symbolic links in the | 
					
						
							|  |  |  |     source tree result in symbolic links in the destination tree; if | 
					
						
							|  |  |  |     it is false, the contents of the files pointed to by symbolic | 
					
						
							|  |  |  |     links are copied. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     XXX Consider this example code rather than the ultimate tool. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											1997-04-29 14:06:46 +00:00
										 |  |  |     names = os.listdir(src) | 
					
						
							| 
									
										
										
										
											2005-01-08 12:31:29 +00:00
										 |  |  |     os.makedirs(dst) | 
					
						
							| 
									
										
										
										
											2002-10-07 13:23:24 +00:00
										 |  |  |     errors = [] | 
					
						
							| 
									
										
										
										
											1997-04-29 14:06:46 +00:00
										 |  |  |     for name in names: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         srcname = os.path.join(src, name) | 
					
						
							|  |  |  |         dstname = os.path.join(dst, name) | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             if symlinks and os.path.islink(srcname): | 
					
						
							|  |  |  |                 linkto = os.readlink(srcname) | 
					
						
							|  |  |  |                 os.symlink(linkto, dstname) | 
					
						
							|  |  |  |             elif os.path.isdir(srcname): | 
					
						
							| 
									
										
										
										
											2000-04-07 14:34:50 +00:00
										 |  |  |                 copytree(srcname, dstname, symlinks) | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |             else: | 
					
						
							|  |  |  |                 copy2(srcname, dstname) | 
					
						
							|  |  |  |             # XXX What about devices, sockets etc.? | 
					
						
							|  |  |  |         except (IOError, os.error), why: | 
					
						
							| 
									
										
										
										
											2006-04-28 16:54:25 +00:00
										 |  |  |             errors.append((srcname, dstname, str(why))) | 
					
						
							| 
									
										
										
										
											2005-08-31 22:48:45 +00:00
										 |  |  |         # catch the Error from the recursive copytree so that we can | 
					
						
							|  |  |  |         # continue with other files | 
					
						
							|  |  |  |         except Error, err: | 
					
						
							|  |  |  |             errors.extend(err.args[0]) | 
					
						
							| 
									
										
										
										
											2006-07-30 13:00:31 +00:00
										 |  |  |     try: | 
					
						
							|  |  |  |         copystat(src, dst) | 
					
						
							|  |  |  |     except WindowsError: | 
					
						
							|  |  |  |         # can't copy file access times on Windows | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     except OSError, why: | 
					
						
							|  |  |  |         errors.extend((src, dst, str(why))) | 
					
						
							| 
									
										
										
										
											2002-10-07 13:23:24 +00:00
										 |  |  |     if errors: | 
					
						
							|  |  |  |         raise Error, errors | 
					
						
							| 
									
										
										
										
											1998-02-06 21:38:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-01-24 17:36:15 +00:00
										 |  |  | def rmtree(path, ignore_errors=False, onerror=None): | 
					
						
							| 
									
										
										
										
											1998-02-06 21:38:09 +00:00
										 |  |  |     """Recursively delete a directory tree.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-10-31 12:05:31 +00:00
										 |  |  |     If ignore_errors is set, errors are ignored; otherwise, if onerror | 
					
						
							|  |  |  |     is set, it is called to handle the error with arguments (func, | 
					
						
							|  |  |  |     path, exc_info) where func is os.listdir, os.remove, or os.rmdir; | 
					
						
							|  |  |  |     path is the argument to that function that caused it to fail; and | 
					
						
							|  |  |  |     exc_info is a tuple returned by sys.exc_info().  If ignore_errors | 
					
						
							|  |  |  |     is false and onerror is None, an exception is raised. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-02-06 21:38:09 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2004-10-31 12:05:31 +00:00
										 |  |  |     if ignore_errors: | 
					
						
							|  |  |  |         def onerror(*args): | 
					
						
							| 
									
										
										
										
											2003-01-24 17:36:15 +00:00
										 |  |  |             pass | 
					
						
							| 
									
										
										
										
											2004-10-31 12:05:31 +00:00
										 |  |  |     elif onerror is None: | 
					
						
							|  |  |  |         def onerror(*args): | 
					
						
							|  |  |  |             raise | 
					
						
							|  |  |  |     names = [] | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         names = os.listdir(path) | 
					
						
							|  |  |  |     except os.error, err: | 
					
						
							|  |  |  |         onerror(os.listdir, path, sys.exc_info()) | 
					
						
							|  |  |  |     for name in names: | 
					
						
							|  |  |  |         fullname = os.path.join(path, name) | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             mode = os.lstat(fullname).st_mode | 
					
						
							|  |  |  |         except os.error: | 
					
						
							|  |  |  |             mode = 0 | 
					
						
							|  |  |  |         if stat.S_ISDIR(mode): | 
					
						
							|  |  |  |             rmtree(fullname, ignore_errors, onerror) | 
					
						
							| 
									
										
										
										
											2003-01-24 17:36:15 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2004-10-31 12:05:31 +00:00
										 |  |  |             try: | 
					
						
							|  |  |  |                 os.remove(fullname) | 
					
						
							|  |  |  |             except os.error, err: | 
					
						
							|  |  |  |                 onerror(os.remove, fullname, sys.exc_info()) | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         os.rmdir(path) | 
					
						
							|  |  |  |     except os.error: | 
					
						
							|  |  |  |         onerror(os.rmdir, path, sys.exc_info()) | 
					
						
							| 
									
										
										
										
											1998-02-06 21:38:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-10-07 13:23:24 +00:00
										 |  |  | def move(src, dst): | 
					
						
							|  |  |  |     """Recursively move a file or directory to another location.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     If the destination is on our current filesystem, then simply use | 
					
						
							|  |  |  |     rename.  Otherwise, copy src to the dst and then remove src. | 
					
						
							|  |  |  |     A lot more could be done here...  A look at a mv.c shows a lot of | 
					
						
							|  |  |  |     the issues this implementation glosses over. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         os.rename(src, dst) | 
					
						
							|  |  |  |     except OSError: | 
					
						
							|  |  |  |         if os.path.isdir(src): | 
					
						
							| 
									
										
										
										
											2004-06-19 21:11:35 +00:00
										 |  |  |             if destinsrc(src, dst): | 
					
						
							|  |  |  |                 raise Error, "Cannot move a directory '%s' into itself '%s'." % (src, dst) | 
					
						
							| 
									
										
										
										
											2003-02-23 21:36:32 +00:00
										 |  |  |             copytree(src, dst, symlinks=True) | 
					
						
							| 
									
										
										
										
											2002-10-07 13:23:24 +00:00
										 |  |  |             rmtree(src) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             copy2(src,dst) | 
					
						
							|  |  |  |             os.unlink(src) | 
					
						
							| 
									
										
										
										
											2004-06-19 21:11:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def destinsrc(src, dst): | 
					
						
							|  |  |  |     return abspath(dst).startswith(abspath(src)) |