| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  | """distutils.file_util
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-09-26 02:03:34 +00:00
										 |  |  | Utility functions for operating on single files. | 
					
						
							|  |  |  | """
 | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # created 2000/04/03, Greg Ward (extracted from util.py) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __revision__ = "$Id$" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import os | 
					
						
							| 
									
										
										
										
											2001-01-31 20:07:17 +00:00
										 |  |  | from stat import * | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  | from distutils.errors import DistutilsFileError | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # for generating verbose output in 'copy_file()' | 
					
						
							|  |  |  | _copy_action = { None:   'copying', | 
					
						
							|  |  |  |                  'hard': 'hard linking', | 
					
						
							|  |  |  |                  'sym':  'symbolically linking' } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _copy_file_contents (src, dst, buffer_size=16*1024): | 
					
						
							|  |  |  |     """Copy the file 'src' to 'dst'; both must be filenames.  Any error
 | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |     opening either file, reading from 'src', or writing to 'dst', raises | 
					
						
							|  |  |  |     DistutilsFileError.  Data is read/written in chunks of 'buffer_size' | 
					
						
							|  |  |  |     bytes (default 16k).  No attempt is made to handle anything apart from | 
					
						
							|  |  |  |     regular files. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |     # Stolen from shutil module in the standard library, but with | 
					
						
							|  |  |  |     # custom error-handling added. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fsrc = None | 
					
						
							|  |  |  |     fdst = None | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             fsrc = open(src, 'rb') | 
					
						
							|  |  |  |         except os.error, (errno, errstr): | 
					
						
							|  |  |  |             raise DistutilsFileError, \ | 
					
						
							|  |  |  |                   "could not open '%s': %s" % (src, errstr) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             fdst = open(dst, 'wb') | 
					
						
							|  |  |  |         except os.error, (errno, errstr): | 
					
						
							|  |  |  |             raise DistutilsFileError, \ | 
					
						
							|  |  |  |                   "could not create '%s': %s" % (dst, errstr) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         while 1: | 
					
						
							|  |  |  |             try: | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |                 buf = fsrc.read(buffer_size) | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |             except os.error, (errno, errstr): | 
					
						
							|  |  |  |                 raise DistutilsFileError, \ | 
					
						
							|  |  |  |                       "could not read from '%s': %s" % (src, errstr) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             if not buf: | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 fdst.write(buf) | 
					
						
							|  |  |  |             except os.error, (errno, errstr): | 
					
						
							|  |  |  |                 raise DistutilsFileError, \ | 
					
						
							|  |  |  |                       "could not write to '%s': %s" % (dst, errstr) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |     finally: | 
					
						
							|  |  |  |         if fdst: | 
					
						
							|  |  |  |             fdst.close() | 
					
						
							|  |  |  |         if fsrc: | 
					
						
							|  |  |  |             fsrc.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # _copy_file_contents() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def copy_file (src, dst, | 
					
						
							|  |  |  |                preserve_mode=1, | 
					
						
							|  |  |  |                preserve_times=1, | 
					
						
							|  |  |  |                update=0, | 
					
						
							|  |  |  |                link=None, | 
					
						
							|  |  |  |                verbose=0, | 
					
						
							|  |  |  |                dry_run=0): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |     """Copy a file 'src' to 'dst'.  If 'dst' is a directory, then 'src' is
 | 
					
						
							|  |  |  |     copied there with the same name; otherwise, it must be a filename.  (If | 
					
						
							|  |  |  |     the file exists, it will be ruthlessly clobbered.)  If 'preserve_mode' | 
					
						
							|  |  |  |     is true (the default), the file's mode (type and permission bits, or | 
					
						
							|  |  |  |     whatever is analogous on the current platform) is copied.  If | 
					
						
							|  |  |  |     'preserve_times' is true (the default), the last-modified and | 
					
						
							|  |  |  |     last-access times are copied as well.  If 'update' is true, 'src' will | 
					
						
							|  |  |  |     only be copied if 'dst' does not exist, or if 'dst' does exist but is | 
					
						
							|  |  |  |     older than 'src'.  If 'verbose' is true, then a one-line summary of the | 
					
						
							|  |  |  |     copy will be printed to stdout. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     'link' allows you to make hard links (os.link) or symbolic links | 
					
						
							|  |  |  |     (os.symlink) instead of copying: set it to "hard" or "sym"; if it is | 
					
						
							|  |  |  |     None (the default), files are copied.  Don't set 'link' on systems that | 
					
						
							|  |  |  |     don't support it: 'copy_file()' doesn't check if hard or symbolic | 
					
						
							|  |  |  |     linking is available. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Under Mac OS, uses the native file copy function in macostools; on | 
					
						
							|  |  |  |     other systems, uses '_copy_file_contents()' to copy file contents. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-09-30 17:29:35 +00:00
										 |  |  |     Return a tuple (dest_name, copied): 'dest_name' is the actual name of | 
					
						
							|  |  |  |     the output file, and 'copied' is true if the file was copied (or would | 
					
						
							|  |  |  |     have been copied, if 'dry_run' true). | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |     # XXX if the destination file already exists, we clobber it if | 
					
						
							|  |  |  |     # copying, but blow up if linking.  Hmmm.  And I don't know what | 
					
						
							|  |  |  |     # macostools.copyfile() does.  Should definitely be consistent, and | 
					
						
							|  |  |  |     # should probably blow up if destination exists and we would be | 
					
						
							|  |  |  |     # changing it (ie. it's not already a hard/soft link to src OR | 
					
						
							|  |  |  |     # (not update) and (src newer than dst). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     from distutils.dep_util import newer | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |     if not os.path.isfile(src): | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |         raise DistutilsFileError, \ | 
					
						
							|  |  |  |               "can't copy '%s': doesn't exist or not a regular file" % src | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |     if os.path.isdir(dst): | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |         dir = dst | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |         dst = os.path.join(dst, os.path.basename(src)) | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |         dir = os.path.dirname(dst) | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |     if update and not newer(src, dst): | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |         if verbose: | 
					
						
							|  |  |  |             print "not copying %s (output up-to-date)" % src | 
					
						
							| 
									
										
										
										
											2000-09-30 17:29:35 +00:00
										 |  |  |         return (dst, 0) | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         action = _copy_action[link] | 
					
						
							|  |  |  |     except KeyError: | 
					
						
							|  |  |  |         raise ValueError, \ | 
					
						
							|  |  |  |               "invalid value '%s' for 'link' argument" % link | 
					
						
							|  |  |  |     if verbose: | 
					
						
							| 
									
										
										
										
											2000-05-20 16:05:34 +00:00
										 |  |  |         if os.path.basename(dst) == os.path.basename(src): | 
					
						
							|  |  |  |             print "%s %s -> %s" % (action, src, dir) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             print "%s %s -> %s" % (action, src, dst) | 
					
						
							|  |  |  |              | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |     if dry_run: | 
					
						
							| 
									
										
										
										
											2000-09-30 17:29:35 +00:00
										 |  |  |         return (dst, 1) | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-09-30 17:29:35 +00:00
										 |  |  |     # On Mac OS, use the native file copy routine | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |     if os.name == 'mac': | 
					
						
							|  |  |  |         import macostools | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |             macostools.copy(src, dst, 0, preserve_times) | 
					
						
							| 
									
										
										
										
											2000-04-22 15:17:14 +00:00
										 |  |  |         except os.error, exc: | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |             raise DistutilsFileError, \ | 
					
						
							|  |  |  |                   "could not copy '%s' to '%s': %s" % (src, dst, exc[-1]) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     # If linking (hard or symbolic), use the appropriate system call | 
					
						
							|  |  |  |     # (Unix only, of course, but that's the caller's responsibility) | 
					
						
							|  |  |  |     elif link == 'hard': | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |         if not (os.path.exists(dst) and os.path.samefile(src, dst)): | 
					
						
							|  |  |  |             os.link(src, dst) | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |     elif link == 'sym': | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |         if not (os.path.exists(dst) and os.path.samefile(src, dst)): | 
					
						
							|  |  |  |             os.symlink(src, dst) | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Otherwise (non-Mac, not linking), copy the file contents and | 
					
						
							|  |  |  |     # (optionally) copy the times and mode. | 
					
						
							|  |  |  |     else: | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |         _copy_file_contents(src, dst) | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |         if preserve_mode or preserve_times: | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |             st = os.stat(src) | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # According to David Ascher <da@ski.org>, utime() should be done | 
					
						
							|  |  |  |             # before chmod() (at least under NT). | 
					
						
							|  |  |  |             if preserve_times: | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |                 os.utime(dst, (st[ST_ATIME], st[ST_MTIME])) | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |             if preserve_mode: | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |                 os.chmod(dst, S_IMODE(st[ST_MODE])) | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-09-30 17:29:35 +00:00
										 |  |  |     return (dst, 1) | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # copy_file () | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # XXX I suspect this is Unix-specific -- need porting help! | 
					
						
							|  |  |  | def move_file (src, dst, | 
					
						
							|  |  |  |                verbose=0, | 
					
						
							|  |  |  |                dry_run=0): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |     """Move a file 'src' to 'dst'.  If 'dst' is a directory, the file will
 | 
					
						
							|  |  |  |     be moved into it with the same name; otherwise, 'src' is just renamed | 
					
						
							|  |  |  |     to 'dst'.  Return the new full name of the file. | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |     Handles cross-device moves on Unix using 'copy_file()'.  What about | 
					
						
							|  |  |  |     other systems??? | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |     from os.path import exists, isfile, isdir, basename, dirname | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if verbose: | 
					
						
							|  |  |  |         print "moving %s -> %s" % (src, dst) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if dry_run: | 
					
						
							|  |  |  |         return dst | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |     if not isfile(src): | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |         raise DistutilsFileError, \ | 
					
						
							|  |  |  |               "can't move '%s': not a regular file" % src | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |     if isdir(dst): | 
					
						
							|  |  |  |         dst = os.path.join(dst, basename(src)) | 
					
						
							|  |  |  |     elif exists(dst): | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |         raise DistutilsFileError, \ | 
					
						
							|  |  |  |               "can't move '%s': destination '%s' already exists" % \ | 
					
						
							|  |  |  |               (src, dst) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |     if not isdir(dirname(dst)): | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |         raise DistutilsFileError, \ | 
					
						
							|  |  |  |               "can't move '%s': destination '%s' not a valid path" % \ | 
					
						
							|  |  |  |               (src, dst) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     copy_it = 0 | 
					
						
							|  |  |  |     try: | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |         os.rename(src, dst) | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |     except os.error, (num, msg): | 
					
						
							|  |  |  |         if num == errno.EXDEV: | 
					
						
							|  |  |  |             copy_it = 1 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise DistutilsFileError, \ | 
					
						
							|  |  |  |                   "couldn't move '%s' to '%s': %s" % (src, dst, msg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if copy_it: | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |         copy_file(src, dst) | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |             os.unlink(src) | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |         except os.error, (num, msg): | 
					
						
							|  |  |  |             try: | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |                 os.unlink(dst) | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |             except os.error: | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  |             raise DistutilsFileError, \ | 
					
						
							|  |  |  |                   ("couldn't move '%s' to '%s' by copy/delete: " +  | 
					
						
							|  |  |  |                    "delete '%s' failed: %s") % \ | 
					
						
							|  |  |  |                   (src, dst, src, msg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return dst | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # move_file () | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def write_file (filename, contents): | 
					
						
							|  |  |  |     """Create a file with the specified name and write 'contents' (a
 | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |     sequence of strings without line terminators) to it. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     f = open(filename, "w") | 
					
						
							| 
									
										
										
										
											2000-04-04 02:05:59 +00:00
										 |  |  |     for line in contents: | 
					
						
							| 
									
										
										
										
											2000-09-23 00:59:34 +00:00
										 |  |  |         f.write(line + "\n") | 
					
						
							|  |  |  |     f.close() |