| Left: | ||
| Right: |
| LEFT | RIGHT |
|---|---|
| 1 """Utility functions for copying and archiving files and directory trees. | 1 """Utility functions for copying and archiving files and directory trees. |
| 2 | 2 |
| 3 XXX The functions here don't copy the resource fork or other metadata on Mac. | 3 XXX The functions here don't copy the resource fork or other metadata on Mac. |
| 4 | 4 |
| 5 """ | 5 """ |
| 6 | 6 |
| 7 import os | 7 import os |
| 8 import sys | 8 import sys |
| 9 import stat | 9 import stat |
| 10 from os.path import abspath | 10 from os.path import abspath |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 75 if hasattr(os.path, 'samefile'): | 75 if hasattr(os.path, 'samefile'): |
| 76 try: | 76 try: |
| 77 return os.path.samefile(src, dst) | 77 return os.path.samefile(src, dst) |
| 78 except OSError: | 78 except OSError: |
| 79 return False | 79 return False |
| 80 | 80 |
| 81 # All other platforms: check for same pathname. | 81 # All other platforms: check for same pathname. |
| 82 return (os.path.normcase(os.path.abspath(src)) == | 82 return (os.path.normcase(os.path.abspath(src)) == |
| 83 os.path.normcase(os.path.abspath(dst))) | 83 os.path.normcase(os.path.abspath(dst))) |
| 84 | 84 |
| 85 def copyfile(src, dst, follow_symlinks=True): | 85 def copyfile(src, dst, *, follow_symlinks=True): |
|
larry
2012/07/01 17:44:36
follow_symlinks should always be keyword-only. Pl
| |
| 86 """Copy data from src to dst. | 86 """Copy data from src to dst. |
| 87 | 87 |
| 88 If optional flag `follow_symlinks` is not set and `src` is a symbolic link, a new | 88 If optional flag `follow_symlinks` is not set and `src` is a symbolic link, a new |
|
larry
2012/07/01 17:44:36
Please change this paragraph to:
"""
If follow_sy
| |
| 89 symlink will be created instead of copying the file it points to. | 89 symlink will be created instead of copying the file it points to. |
| 90 | 90 |
| 91 """ | 91 """ |
| 92 if _samefile(src, dst): | 92 if _samefile(src, dst): |
| 93 raise Error("`%s` and `%s` are the same file" % (src, dst)) | 93 raise Error("`%s` and `%s` are the same file" % (src, dst)) |
| 94 | 94 |
| 95 for fn in [src, dst]: | 95 for fn in [src, dst]: |
| 96 try: | 96 try: |
| 97 st = os.stat(fn) | 97 st = os.stat(fn) |
| 98 except OSError: | 98 except OSError: |
| 99 # File most likely does not exist | 99 # File most likely does not exist |
| 100 pass | 100 pass |
| 101 else: | 101 else: |
| 102 # XXX What about other special files? (sockets, devices...) | 102 # XXX What about other special files? (sockets, devices...) |
| 103 if stat.S_ISFIFO(st.st_mode): | 103 if stat.S_ISFIFO(st.st_mode): |
| 104 raise SpecialFileError("`%s` is a named pipe" % fn) | 104 raise SpecialFileError("`%s` is a named pipe" % fn) |
| 105 | 105 |
| 106 if not follow_symlinks and os.path.islink(src): | 106 if not follow_symlinks and os.path.islink(src): |
| 107 os.symlink(os.readlink(src), dst) | 107 os.symlink(os.readlink(src), dst) |
| 108 else: | 108 else: |
| 109 with open(src, 'rb') as fsrc: | 109 with open(src, 'rb') as fsrc: |
| 110 with open(dst, 'wb') as fdst: | 110 with open(dst, 'wb') as fdst: |
| 111 copyfileobj(fsrc, fdst) | 111 copyfileobj(fsrc, fdst) |
| 112 return dst | 112 return dst |
| 113 | 113 |
| 114 def copymode(src, dst, follow_symlinks=True): | 114 def copymode(src, dst, *, follow_symlinks=True): |
| 115 """Copy mode bits from src to dst. | 115 """Copy mode bits from src to dst. |
| 116 | 116 |
| 117 If the optional flag `follow_symlinks` is not set, symlinks aren't followed if and | 117 If the optional flag `follow_symlinks` is not set, symlinks aren't followed if and |
|
larry
2012/07/01 17:44:36
Please change this paragraph to:
"""
If follow_sy
| |
| 118 only if both `src` and `dst` are symlinks. If `lchmod` isn't available (eg. | 118 only if both `src` and `dst` are symlinks. If `lchmod` isn't available (eg. |
| 119 Linux), in these cases, this method does nothing. | 119 Linux), in these cases, this method does nothing. |
| 120 | 120 |
| 121 """ | 121 """ |
| 122 if not follow_symlinks and os.path.islink(src) and os.path.islink(dst): | 122 if not follow_symlinks and os.path.islink(src) and os.path.islink(dst): |
| 123 if hasattr(os, 'lchmod'): | 123 if hasattr(os, 'lchmod'): |
| 124 stat_func, chmod_func = os.lstat, os.lchmod | 124 stat_func, chmod_func = os.lstat, os.lchmod |
| 125 else: | 125 else: |
| 126 return | 126 return |
| 127 elif hasattr(os, 'chmod'): | 127 elif hasattr(os, 'chmod'): |
| 128 stat_func, chmod_func = os.stat, os.chmod | 128 stat_func, chmod_func = os.stat, os.chmod |
| 129 else: | 129 else: |
| 130 return | 130 return |
| 131 | 131 |
| 132 st = stat_func(src) | 132 st = stat_func(src) |
| 133 chmod_func(dst, stat.S_IMODE(st.st_mode)) | 133 chmod_func(dst, stat.S_IMODE(st.st_mode)) |
| 134 | 134 |
| 135 def copystat(src, dst, follow_symlinks=True): | 135 def copystat(src, dst, *, follow_symlinks=True): |
| 136 """Copy all stat info (mode bits, atime, mtime, flags) from src to dst. | 136 """Copy all stat info (mode bits, atime, mtime, flags) from src to dst. |
| 137 | 137 |
| 138 If the optional flag `follow_symlinks` is not set, symlinks aren't followed if and | 138 If the optional flag `follow_symlinks` is not set, symlinks aren't followed if and |
|
larry
2012/07/01 17:44:36
Please change to:
"""
If follow_symlinks is False
| |
| 139 only if both `src` and `dst` are symlinks. | 139 only if both `src` and `dst` are symlinks. |
| 140 | 140 |
| 141 """ | 141 """ |
| 142 def _nop(*args, ns=None, follow_symlinks=None): | 142 def _nop(*args, ns=None, follow_symlinks=None): |
| 143 pass | 143 pass |
| 144 | 144 |
| 145 # follow symlinks (aka don't not follow symlinks) | 145 # follow symlinks (aka don't not follow symlinks) |
| 146 follow = follow_symlinks or not (os.path.islink(src) and os.path.islink(dst) ) | 146 follow = follow_symlinks or not (os.path.islink(src) and os.path.islink(dst) ) |
| 147 if follow: | 147 if follow: |
| 148 # use the real function if it exists | 148 # use the real function if it exists |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 179 try: | 179 try: |
| 180 lookup("chflags")(dst, st.st_flags, follow_symlinks=follow) | 180 lookup("chflags")(dst, st.st_flags, follow_symlinks=follow) |
| 181 except OSError as why: | 181 except OSError as why: |
| 182 for err in 'EOPNOTSUPP', 'ENOTSUP': | 182 for err in 'EOPNOTSUPP', 'ENOTSUP': |
| 183 if hasattr(errno, err) and why.errno == getattr(errno, err): | 183 if hasattr(errno, err) and why.errno == getattr(errno, err): |
| 184 break | 184 break |
| 185 else: | 185 else: |
| 186 raise | 186 raise |
| 187 | 187 |
| 188 if hasattr(os, 'listxattr'): | 188 if hasattr(os, 'listxattr'): |
| 189 def _copyxattr(src, dst, follow_symlinks=True): | 189 def _copyxattr(src, dst, *, follow_symlinks=True): |
| 190 """Copy extended filesystem attributes from `src` to `dst`. | 190 """Copy extended filesystem attributes from `src` to `dst`. |
| 191 | 191 |
| 192 Overwrite existing attributes. | 192 Overwrite existing attributes. |
| 193 | 193 |
| 194 If the optional flag `follow_symlinks` is not set, symlinks won't be fol lowed. | 194 If the optional flag `follow_symlinks` is not set, symlinks won't be fol lowed. |
| 195 | 195 |
| 196 """ | 196 """ |
| 197 | 197 |
| 198 for name in os.listxattr(src, follow_symlinks=follow_symlinks): | 198 for name in os.listxattr(src, follow_symlinks=follow_symlinks): |
| 199 try: | 199 try: |
| 200 value = os.getxattr(src, name, follow_symlinks=follow_symlinks) | 200 value = os.getxattr(src, name, follow_symlinks=follow_symlinks) |
| 201 os.setxattr(dst, name, value, follow_symlinks=follow_symlinks) | 201 os.setxattr(dst, name, value, follow_symlinks=follow_symlinks) |
| 202 except OSError as e: | 202 except OSError as e: |
| 203 if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA): | 203 if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA): |
| 204 raise | 204 raise |
| 205 else: | 205 else: |
| 206 def _copyxattr(*args, **kwargs): | 206 def _copyxattr(*args, **kwargs): |
| 207 pass | 207 pass |
| 208 | 208 |
| 209 def copy(src, dst, follow_symlinks=True): | 209 def copy(src, dst, *, follow_symlinks=True): |
| 210 """Copy data and mode bits ("cp src dst"). Return the file's destination. | 210 """Copy data and mode bits ("cp src dst"). Return the file's destination. |
| 211 | 211 |
| 212 The destination may be a directory. | 212 The destination may be a directory. |
| 213 | 213 |
| 214 If the optional flag `follow_symlinks` is not set, symlinks won't be followe d. This | 214 If the optional flag `follow_symlinks` is not set, symlinks won't be followe d. This |
| 215 resembles GNU's "cp -P src dst". | 215 resembles GNU's "cp -P src dst". |
| 216 | 216 |
| 217 """ | 217 """ |
| 218 if os.path.isdir(dst): | 218 if os.path.isdir(dst): |
| 219 dst = os.path.join(dst, os.path.basename(src)) | 219 dst = os.path.join(dst, os.path.basename(src)) |
| 220 copyfile(src, dst, follow_symlinks=follow_symlinks) | 220 copyfile(src, dst, follow_symlinks=follow_symlinks) |
| 221 copymode(src, dst, follow_symlinks=follow_symlinks) | 221 copymode(src, dst, follow_symlinks=follow_symlinks) |
| 222 return dst | 222 return dst |
| 223 | 223 |
| 224 def copy2(src, dst, follow_symlinks=True): | 224 def copy2(src, dst, *, follow_symlinks=True): |
| 225 """Copy data and all stat info ("cp -p src dst"). Return the file's | 225 """Copy data and all stat info ("cp -p src dst"). Return the file's |
| 226 destination." | 226 destination." |
| 227 | 227 |
| 228 The destination may be a directory. | 228 The destination may be a directory. |
| 229 | 229 |
| 230 If the optional flag `follow_symlinks` is not set, symlinks won't be followe d. This | 230 If the optional flag `follow_symlinks` is not set, symlinks won't be followe d. This |
| 231 resembles GNU's "cp -P src dst". | 231 resembles GNU's "cp -P src dst". |
| 232 | 232 |
| 233 """ | 233 """ |
| 234 if os.path.isdir(dst): | 234 if os.path.isdir(dst): |
| (...skipping 858 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1093 seen = set() | 1093 seen = set() |
| 1094 for dir in path: | 1094 for dir in path: |
| 1095 dir = os.path.normcase(dir) | 1095 dir = os.path.normcase(dir) |
| 1096 if not dir in seen: | 1096 if not dir in seen: |
| 1097 seen.add(dir) | 1097 seen.add(dir) |
| 1098 for thefile in files: | 1098 for thefile in files: |
| 1099 name = os.path.join(dir, thefile) | 1099 name = os.path.join(dir, thefile) |
| 1100 if _access_check(name, mode): | 1100 if _access_check(name, mode): |
| 1101 return name | 1101 return name |
| 1102 return None | 1102 return None |
| LEFT | RIGHT |