00001 ## 00002 # Utility functions for copying files and directory trees on remote servers via sshUtils. 00003 # 00004 # XXX The functions here don't copy the resource fork or other metadata on Mac. 00005 # 00006 # 00007 00008 import sshUtils as os 00009 import sys 00010 import stat 00011 from os.path import abspath 00012 00013 __all__ = ["copyfileobj","copyfile","copymode","copystat","copy","copy2", 00014 "copytree","move","rmtree","Error"] 00015 00016 class Error(EnvironmentError): 00017 pass 00018 00019 ## 00020 # copy data from file-like object fsrc to file-like object fdst 00021 def copyfileobj(fsrc, fdst, length=16*1024): 00022 while 1: 00023 buf = fsrc.read(length) 00024 if not buf: 00025 break 00026 fdst.write(buf) 00027 00028 def _samefile(src, dst): 00029 # Macintosh, Unix. 00030 if hasattr(os.path,'samefile'): 00031 try: 00032 return os.path.samefile(src, dst) 00033 except OSError: 00034 return False 00035 00036 # All other platforms: check for same pathname. 00037 return (os.path.normcase(os.path.abspath(src)) == 00038 os.path.normcase(os.path.abspath(dst))) 00039 00040 ## 00041 # Copy data from src to dst 00042 def copyfile(src, dst): 00043 if _samefile(src, dst): 00044 raise Error, "`%s` and `%s` are the same file" % (src, dst) 00045 00046 fsrc = None 00047 fdst = None 00048 try: 00049 fsrc = open(src, 'rb') 00050 fdst = open(dst, 'wb') 00051 copyfileobj(fsrc, fdst) 00052 finally: 00053 if fdst: 00054 fdst.close() 00055 if fsrc: 00056 fsrc.close() 00057 00058 ## 00059 # Copy mode bits from src to dst 00060 def copymode(src, dst): 00061 if hasattr(os, 'chmod'): 00062 st = os.stat(src) 00063 mode = stat.S_IMODE(st.st_mode) 00064 os.chmod(dst, mode) 00065 00066 ## 00067 # Copy all stat info (mode bits, atime and mtime) from src to dst 00068 def copystat(src, dst): 00069 st = os.stat(src) 00070 mode = stat.S_IMODE(st.st_mode) 00071 if hasattr(os, 'utime'): 00072 os.utime(dst, (st.st_atime, st.st_mtime)) 00073 if hasattr(os, 'chmod'): 00074 os.chmod(dst, mode) 00075 00076 00077 ## 00078 # Copy data and mode bits ("cp src dst"). 00079 # 00080 # The destination may be a directory. 00081 # 00082 # 00083 def copy(src, dst): 00084 if os.path.isdir(dst): 00085 dst = os.path.join(dst, os.path.basename(src)) 00086 copyfile(src, dst) 00087 copymode(src, dst) 00088 00089 ## 00090 # Copy data and all stat info ("cp -p src dst"). 00091 # 00092 # The destination may be a directory. 00093 # 00094 # 00095 def copy2(src, dst): 00096 if os.path.isdir(dst): 00097 dst = os.path.join(dst, os.path.basename(src)) 00098 copyfile(src, dst) 00099 copystat(src, dst) 00100 00101 00102 ## 00103 # Recursively copy a directory tree using copy2(). 00104 # 00105 # The destination directory must not already exist. 00106 # If exception(s) occur, an Error is raised with a list of reasons. 00107 # 00108 # If the optional symlinks flag is true, symbolic links in the 00109 # source tree result in symbolic links in the destination tree; if 00110 # it is false, the contents of the files pointed to by symbolic 00111 # links are copied. 00112 # 00113 # XXX Consider this example code rather than the ultimate tool. 00114 # 00115 # 00116 def copytree(src, dst, symlinks=False): 00117 names = os.listdir(src) 00118 os.makedirs(dst) 00119 errors = [] 00120 for name in names: 00121 srcname = os.path.join(src, name) 00122 dstname = os.path.join(dst, name) 00123 try: 00124 if symlinks and os.path.islink(srcname): 00125 linkto = os.readlink(srcname) 00126 os.symlink(linkto, dstname) 00127 elif os.path.isdir(srcname): 00128 copytree(srcname, dstname, symlinks) 00129 else: 00130 copy2(srcname, dstname) 00131 # XXX What about devices, sockets etc.? 00132 except (IOError, os.error), why: 00133 errors.append((srcname, dstname, str(why))) 00134 # catch the Error from the recursive copytree so that we can 00135 # continue with other files 00136 except Error, err: 00137 errors.extend(err.args[0]) 00138 try: 00139 copystat(src, dst) 00140 except WindowsError: 00141 # can't copy file access times on Windows 00142 pass 00143 except OSError, why: 00144 errors.extend((src, dst, str(why))) 00145 if errors: 00146 raise Error, errors 00147 00148 ## 00149 # Recursively delete a directory tree. 00150 # 00151 # If ignore_errors is set, errors are ignored; otherwise, if onerror 00152 # is set, it is called to handle the error with arguments (func, 00153 # path, exc_info) where func is os.listdir, os.remove, or os.rmdir; 00154 # path is the argument to that function that caused it to fail; and 00155 # exc_info is a tuple returned by sys.exc_info(). If ignore_errors 00156 # is false and onerror is None, an exception is raised. 00157 # 00158 # 00159 def rmtree(path, ignore_errors=False, onerror=None): 00160 if ignore_errors: 00161 def onerror(*args): 00162 pass 00163 elif onerror is None: 00164 def onerror(*args): 00165 raise 00166 names = [] 00167 try: 00168 names = os.listdir(path) 00169 except os.error, err: 00170 onerror(os.listdir, path, sys.exc_info()) 00171 for name in names: 00172 fullname = os.path.join(path, name) 00173 try: 00174 mode = os.lstat(fullname).st_mode 00175 except os.error: 00176 mode = 0 00177 if stat.S_ISDIR(mode): 00178 rmtree(fullname, ignore_errors, onerror) 00179 else: 00180 try: 00181 os.remove(fullname) 00182 except os.error, err: 00183 onerror(os.remove, fullname, sys.exc_info()) 00184 try: 00185 os.rmdir(path) 00186 except os.error: 00187 onerror(os.rmdir, path, sys.exc_info()) 00188 00189 ## 00190 # Recursively move a file or directory to another location. 00191 # 00192 # If the destination is on our current filesystem, then simply use 00193 # rename. Otherwise, copy src to the dst and then remove src. 00194 # A lot more could be done here... A look at a mv.c shows a lot of 00195 # the issues this implementation glosses over. 00196 # 00197 # 00198 def move(src, dst): 00199 00200 try: 00201 os.rename(src, dst) 00202 except OSError: 00203 if os.path.isdir(src): 00204 if destinsrc(src, dst): 00205 raise Error, "Cannot move a directory '%s' into itself '%s'." % (src, dst) 00206 copytree(src, dst, symlinks=True) 00207 rmtree(src) 00208 else: 00209 copy2(src,dst) 00210 os.unlink(src) 00211 00212 def destinsrc(src, dst): 00213 return abspath(dst).startswith(abspath(src)) 00214 00215
© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved; If you reference this document or any part of this document you must use the citation verbatim (including the link) "© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved."
Notice: This source code contained in this document is NOT open source and is NOT being distributed as open source.
122,241 lines of code and growing...