blob: 27239f67b7b31fccbfa8de5f46d2d83021bc13a7 [file] [log] [blame]
Tarek Ziadéc3399782010-02-23 05:39:18 +00001"""Utility functions for copying and archiving files and directory trees.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +00002
Guido van Rossum959fa011999-08-18 20:03:17 +00003XXX The functions here don't copy the resource fork or other metadata on Mac.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +00004
5"""
Guido van Rossumc6360141990-10-13 19:23:40 +00006
Guido van Rossumc96207a1992-03-31 18:55:40 +00007import os
Guido van Rossum83c03e21999-02-23 23:07:51 +00008import sys
Guido van Rossum9d0a3df1997-04-29 14:45:19 +00009import stat
Brett Cannon1c3fa182004-06-19 21:11:35 +000010from os.path import abspath
Georg Brandl2ee470f2008-07-16 12:55:28 +000011import fnmatch
Tarek Ziadé396fad72010-02-23 05:30:31 +000012import collections
Antoine Pitrou910bd512010-03-22 20:11:09 +000013import errno
Tarek Ziadé6ac91722010-04-28 17:51:36 +000014import tarfile
Tarek Ziadé396fad72010-02-23 05:30:31 +000015
16try:
Tarek Ziadéffa155a2010-04-29 13:34:35 +000017 import bz2
Florent Xicluna54540ec2011-11-04 08:29:17 +010018 del bz2
Tarek Ziadéffa155a2010-04-29 13:34:35 +000019 _BZ2_SUPPORTED = True
20except ImportError:
21 _BZ2_SUPPORTED = False
22
23try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000024 from pwd import getpwnam
25except ImportError:
26 getpwnam = None
27
28try:
29 from grp import getgrnam
30except ImportError:
31 getgrnam = None
Guido van Rossumc6360141990-10-13 19:23:40 +000032
Tarek Ziadéc3399782010-02-23 05:39:18 +000033__all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2",
34 "copytree", "move", "rmtree", "Error", "SpecialFileError",
35 "ExecError", "make_archive", "get_archive_formats",
Tarek Ziadé6ac91722010-04-28 17:51:36 +000036 "register_archive_format", "unregister_archive_format",
37 "get_unpack_formats", "register_unpack_format",
Éric Araujoc5efe652011-08-21 14:30:00 +020038 "unregister_unpack_format", "unpack_archive",
Brian Curtinc57a3452012-06-22 16:00:30 -050039 "ignore_patterns", "chown", "which"]
Éric Araujoe4d5b8e2011-08-08 16:51:11 +020040 # disk_usage is added later, if available on the platform
Martin v. Löwise9ce0b02002-10-07 13:23:24 +000041
Neal Norwitz4ce69a52005-09-01 00:45:28 +000042class Error(EnvironmentError):
Martin v. Löwise9ce0b02002-10-07 13:23:24 +000043 pass
Guido van Rossumc6360141990-10-13 19:23:40 +000044
Hynek Schlawack48653762012-10-07 12:49:58 +020045class SameFileError(Error):
46 """Raised when source and destination are the same file."""
47
Antoine Pitrou7fff0962009-05-01 21:09:44 +000048class SpecialFileError(EnvironmentError):
49 """Raised when trying to do a kind of operation (e.g. copying) which is
50 not supported on a special file (e.g. a named pipe)"""
51
Tarek Ziadé396fad72010-02-23 05:30:31 +000052class ExecError(EnvironmentError):
53 """Raised when a command could not be executed"""
54
Tarek Ziadé6ac91722010-04-28 17:51:36 +000055class ReadError(EnvironmentError):
56 """Raised when an archive cannot be read"""
57
58class RegistryError(Exception):
59 """Raised when a registery operation with the archiving
60 and unpacking registeries fails"""
61
62
Georg Brandl6aa2d1f2008-08-12 08:35:52 +000063try:
64 WindowsError
65except NameError:
66 WindowsError = None
67
Greg Stein42bb8b32000-07-12 09:55:30 +000068def copyfileobj(fsrc, fdst, length=16*1024):
69 """copy data from file-like object fsrc to file-like object fdst"""
70 while 1:
71 buf = fsrc.read(length)
72 if not buf:
73 break
74 fdst.write(buf)
75
Johannes Gijsbers46f14592004-08-14 13:30:02 +000076def _samefile(src, dst):
77 # Macintosh, Unix.
Tarek Ziadé1eab9cc2010-04-19 21:19:57 +000078 if hasattr(os.path, 'samefile'):
Johannes Gijsbersf9a098e2004-08-14 14:51:01 +000079 try:
80 return os.path.samefile(src, dst)
81 except OSError:
82 return False
Johannes Gijsbers46f14592004-08-14 13:30:02 +000083
84 # All other platforms: check for same pathname.
85 return (os.path.normcase(os.path.abspath(src)) ==
86 os.path.normcase(os.path.abspath(dst)))
Tim Peters495ad3c2001-01-15 01:36:40 +000087
Larry Hastingsb4038062012-07-15 10:57:38 -070088def copyfile(src, dst, *, follow_symlinks=True):
Antoine Pitrou78091e62011-12-29 18:54:15 +010089 """Copy data from src to dst.
90
Larry Hastingsb4038062012-07-15 10:57:38 -070091 If follow_symlinks is not set and src is a symbolic link, a new
Antoine Pitrou78091e62011-12-29 18:54:15 +010092 symlink will be created instead of copying the file it points to.
93
94 """
Johannes Gijsbers46f14592004-08-14 13:30:02 +000095 if _samefile(src, dst):
Hynek Schlawack48653762012-10-07 12:49:58 +020096 raise SameFileError("{!r} and {!r} are the same file".format(src, dst))
Johannes Gijsbers46f14592004-08-14 13:30:02 +000097
Antoine Pitrou7fff0962009-05-01 21:09:44 +000098 for fn in [src, dst]:
99 try:
100 st = os.stat(fn)
101 except OSError:
102 # File most likely does not exist
103 pass
Benjamin Petersonc0d98aa2009-06-05 19:13:27 +0000104 else:
105 # XXX What about other special files? (sockets, devices...)
106 if stat.S_ISFIFO(st.st_mode):
107 raise SpecialFileError("`%s` is a named pipe" % fn)
Tarek Ziadéb01142b2010-05-05 22:43:04 +0000108
Larry Hastingsb4038062012-07-15 10:57:38 -0700109 if not follow_symlinks and os.path.islink(src):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100110 os.symlink(os.readlink(src), dst)
111 else:
112 with open(src, 'rb') as fsrc:
113 with open(dst, 'wb') as fdst:
114 copyfileobj(fsrc, fdst)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500115 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000116
Larry Hastingsb4038062012-07-15 10:57:38 -0700117def copymode(src, dst, *, follow_symlinks=True):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100118 """Copy mode bits from src to dst.
Guido van Rossumc6360141990-10-13 19:23:40 +0000119
Larry Hastingsb4038062012-07-15 10:57:38 -0700120 If follow_symlinks is not set, symlinks aren't followed if and only
121 if both `src` and `dst` are symlinks. If `lchmod` isn't available
122 (e.g. Linux) this method does nothing.
Antoine Pitrou78091e62011-12-29 18:54:15 +0100123
124 """
Larry Hastingsb4038062012-07-15 10:57:38 -0700125 if not follow_symlinks and os.path.islink(src) and os.path.islink(dst):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100126 if hasattr(os, 'lchmod'):
127 stat_func, chmod_func = os.lstat, os.lchmod
128 else:
129 return
130 elif hasattr(os, 'chmod'):
131 stat_func, chmod_func = os.stat, os.chmod
132 else:
133 return
134
135 st = stat_func(src)
136 chmod_func(dst, stat.S_IMODE(st.st_mode))
137
Larry Hastingsad5ae042012-07-14 17:55:11 -0700138if hasattr(os, 'listxattr'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700139 def _copyxattr(src, dst, *, follow_symlinks=True):
Larry Hastingsad5ae042012-07-14 17:55:11 -0700140 """Copy extended filesystem attributes from `src` to `dst`.
141
142 Overwrite existing attributes.
143
Larry Hastingsb4038062012-07-15 10:57:38 -0700144 If `follow_symlinks` is false, symlinks won't be followed.
Larry Hastingsad5ae042012-07-14 17:55:11 -0700145
146 """
147
Larry Hastingsb4038062012-07-15 10:57:38 -0700148 for name in os.listxattr(src, follow_symlinks=follow_symlinks):
Larry Hastingsad5ae042012-07-14 17:55:11 -0700149 try:
Larry Hastingsb4038062012-07-15 10:57:38 -0700150 value = os.getxattr(src, name, follow_symlinks=follow_symlinks)
151 os.setxattr(dst, name, value, follow_symlinks=follow_symlinks)
Larry Hastingsad5ae042012-07-14 17:55:11 -0700152 except OSError as e:
153 if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA):
154 raise
155else:
156 def _copyxattr(*args, **kwargs):
157 pass
158
Larry Hastingsb4038062012-07-15 10:57:38 -0700159def copystat(src, dst, *, follow_symlinks=True):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100160 """Copy all stat info (mode bits, atime, mtime, flags) from src to dst.
161
Larry Hastingsb4038062012-07-15 10:57:38 -0700162 If the optional flag `follow_symlinks` is not set, symlinks aren't followed if and
Antoine Pitrou78091e62011-12-29 18:54:15 +0100163 only if both `src` and `dst` are symlinks.
164
165 """
Larry Hastings9cf065c2012-06-22 16:30:09 -0700166 def _nop(*args, ns=None, follow_symlinks=None):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100167 pass
168
Larry Hastings9cf065c2012-06-22 16:30:09 -0700169 # follow symlinks (aka don't not follow symlinks)
Larry Hastingsb4038062012-07-15 10:57:38 -0700170 follow = follow_symlinks or not (os.path.islink(src) and os.path.islink(dst))
Larry Hastings9cf065c2012-06-22 16:30:09 -0700171 if follow:
172 # use the real function if it exists
173 def lookup(name):
174 return getattr(os, name, _nop)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100175 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700176 # use the real function only if it exists
177 # *and* it supports follow_symlinks
178 def lookup(name):
179 fn = getattr(os, name, _nop)
180 if fn in os.supports_follow_symlinks:
181 return fn
182 return _nop
Antoine Pitrou78091e62011-12-29 18:54:15 +0100183
Larry Hastings9cf065c2012-06-22 16:30:09 -0700184 st = lookup("stat")(src, follow_symlinks=follow)
Walter Dörwald294bbf32002-06-06 09:48:13 +0000185 mode = stat.S_IMODE(st.st_mode)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700186 lookup("utime")(dst, ns=(st.st_atime_ns, st.st_mtime_ns),
187 follow_symlinks=follow)
188 try:
189 lookup("chmod")(dst, mode, follow_symlinks=follow)
190 except NotImplementedError:
191 # if we got a NotImplementedError, it's because
192 # * follow_symlinks=False,
193 # * lchown() is unavailable, and
194 # * either
195 # * fchownat() is unvailable or
196 # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW.
197 # (it returned ENOSUP.)
198 # therefore we're out of options--we simply cannot chown the
199 # symlink. give up, suppress the error.
200 # (which is what shutil always did in this circumstance.)
201 pass
Antoine Pitrou78091e62011-12-29 18:54:15 +0100202 if hasattr(st, 'st_flags'):
Antoine Pitrou910bd512010-03-22 20:11:09 +0000203 try:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700204 lookup("chflags")(dst, st.st_flags, follow_symlinks=follow)
Antoine Pitrou910bd512010-03-22 20:11:09 +0000205 except OSError as why:
Ned Deilybaf75712012-05-10 17:05:19 -0700206 for err in 'EOPNOTSUPP', 'ENOTSUP':
207 if hasattr(errno, err) and why.errno == getattr(errno, err):
208 break
209 else:
Antoine Pitrou910bd512010-03-22 20:11:09 +0000210 raise
Larry Hastingsb4038062012-07-15 10:57:38 -0700211 _copyxattr(src, dst, follow_symlinks=follow)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200212
Larry Hastingsb4038062012-07-15 10:57:38 -0700213def copy(src, dst, *, follow_symlinks=True):
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500214 """Copy data and mode bits ("cp src dst"). Return the file's destination.
Tim Peters495ad3c2001-01-15 01:36:40 +0000215
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000216 The destination may be a directory.
217
Larry Hastingsb4038062012-07-15 10:57:38 -0700218 If follow_symlinks is false, symlinks won't be followed. This
Antoine Pitrou78091e62011-12-29 18:54:15 +0100219 resembles GNU's "cp -P src dst".
220
Hynek Schlawack48653762012-10-07 12:49:58 +0200221 If source and destination are the same file, a SameFileError will be
222 raised.
223
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000224 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000225 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000226 dst = os.path.join(dst, os.path.basename(src))
Larry Hastingsb4038062012-07-15 10:57:38 -0700227 copyfile(src, dst, follow_symlinks=follow_symlinks)
228 copymode(src, dst, follow_symlinks=follow_symlinks)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500229 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000230
Larry Hastingsb4038062012-07-15 10:57:38 -0700231def copy2(src, dst, *, follow_symlinks=True):
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500232 """Copy data and all stat info ("cp -p src dst"). Return the file's
233 destination."
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000234
235 The destination may be a directory.
236
Larry Hastingsb4038062012-07-15 10:57:38 -0700237 If follow_symlinks is false, symlinks won't be followed. This
Antoine Pitrou78091e62011-12-29 18:54:15 +0100238 resembles GNU's "cp -P src dst".
239
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000240 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000241 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000242 dst = os.path.join(dst, os.path.basename(src))
Larry Hastingsb4038062012-07-15 10:57:38 -0700243 copyfile(src, dst, follow_symlinks=follow_symlinks)
244 copystat(src, dst, follow_symlinks=follow_symlinks)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500245 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000246
Georg Brandl2ee470f2008-07-16 12:55:28 +0000247def ignore_patterns(*patterns):
248 """Function that can be used as copytree() ignore parameter.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000249
Georg Brandl2ee470f2008-07-16 12:55:28 +0000250 Patterns is a sequence of glob-style patterns
251 that are used to exclude files"""
252 def _ignore_patterns(path, names):
253 ignored_names = []
254 for pattern in patterns:
255 ignored_names.extend(fnmatch.filter(names, pattern))
256 return set(ignored_names)
257 return _ignore_patterns
258
Tarek Ziadéfb437512010-04-20 08:57:33 +0000259def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
260 ignore_dangling_symlinks=False):
Tarek Ziadé5340db32010-04-19 22:30:51 +0000261 """Recursively copy a directory tree.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000262
263 The destination directory must not already exist.
Neal Norwitza4c93b62003-02-23 21:36:32 +0000264 If exception(s) occur, an Error is raised with a list of reasons.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000265
266 If the optional symlinks flag is true, symbolic links in the
267 source tree result in symbolic links in the destination tree; if
268 it is false, the contents of the files pointed to by symbolic
Tarek Ziadéfb437512010-04-20 08:57:33 +0000269 links are copied. If the file pointed by the symlink doesn't
270 exist, an exception will be added in the list of errors raised in
271 an Error exception at the end of the copy process.
272
273 You can set the optional ignore_dangling_symlinks flag to true if you
Tarek Ziadé8c26c7d2010-04-23 13:03:50 +0000274 want to silence this exception. Notice that this has no effect on
275 platforms that don't support os.symlink.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000276
Georg Brandl2ee470f2008-07-16 12:55:28 +0000277 The optional ignore argument is a callable. If given, it
278 is called with the `src` parameter, which is the directory
279 being visited by copytree(), and `names` which is the list of
280 `src` contents, as returned by os.listdir():
281
282 callable(src, names) -> ignored_names
283
284 Since copytree() is called recursively, the callable will be
285 called once for each directory that is copied. It returns a
286 list of names relative to the `src` directory that should
287 not be copied.
288
Tarek Ziadé5340db32010-04-19 22:30:51 +0000289 The optional copy_function argument is a callable that will be used
290 to copy each file. It will be called with the source path and the
291 destination path as arguments. By default, copy2() is used, but any
292 function that supports the same signature (like copy()) can be used.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000293
294 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000295 names = os.listdir(src)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000296 if ignore is not None:
297 ignored_names = ignore(src, names)
298 else:
299 ignored_names = set()
300
Johannes Gijsberse4172ea2005-01-08 12:31:29 +0000301 os.makedirs(dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000302 errors = []
Guido van Rossuma2baf461997-04-29 14:06:46 +0000303 for name in names:
Georg Brandl2ee470f2008-07-16 12:55:28 +0000304 if name in ignored_names:
305 continue
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000306 srcname = os.path.join(src, name)
307 dstname = os.path.join(dst, name)
308 try:
Tarek Ziadéfb437512010-04-20 08:57:33 +0000309 if os.path.islink(srcname):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000310 linkto = os.readlink(srcname)
Tarek Ziadéfb437512010-04-20 08:57:33 +0000311 if symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100312 # We can't just leave it to `copy_function` because legacy
313 # code with a custom `copy_function` may rely on copytree
314 # doing the right thing.
Tarek Ziadéfb437512010-04-20 08:57:33 +0000315 os.symlink(linkto, dstname)
Larry Hastingsb4038062012-07-15 10:57:38 -0700316 copystat(srcname, dstname, follow_symlinks=not symlinks)
Tarek Ziadéfb437512010-04-20 08:57:33 +0000317 else:
318 # ignore dangling symlink if the flag is on
319 if not os.path.exists(linkto) and ignore_dangling_symlinks:
320 continue
321 # otherwise let the copy occurs. copy2 will raise an error
322 copy_function(srcname, dstname)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000323 elif os.path.isdir(srcname):
Tarek Ziadé5340db32010-04-19 22:30:51 +0000324 copytree(srcname, dstname, symlinks, ignore, copy_function)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000325 else:
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000326 # Will raise a SpecialFileError for unsupported file types
Tarek Ziadé5340db32010-04-19 22:30:51 +0000327 copy_function(srcname, dstname)
Georg Brandla1be88e2005-08-31 22:48:45 +0000328 # catch the Error from the recursive copytree so that we can
329 # continue with other files
Guido van Rossumb940e112007-01-10 16:19:56 +0000330 except Error as err:
Georg Brandla1be88e2005-08-31 22:48:45 +0000331 errors.extend(err.args[0])
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000332 except EnvironmentError as why:
333 errors.append((srcname, dstname, str(why)))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000334 try:
335 copystat(src, dst)
Guido van Rossumb940e112007-01-10 16:19:56 +0000336 except OSError as why:
Georg Brandl6aa2d1f2008-08-12 08:35:52 +0000337 if WindowsError is not None and isinstance(why, WindowsError):
338 # Copying file access times may fail on Windows
339 pass
340 else:
Georg Brandlc8076df2012-08-25 10:11:57 +0200341 errors.append((src, dst, str(why)))
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000342 if errors:
Collin Winterce36ad82007-08-30 01:19:48 +0000343 raise Error(errors)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500344 return dst
Guido van Rossumd7673291998-02-06 21:38:09 +0000345
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200346# version vulnerable to race conditions
347def _rmtree_unsafe(path, onerror):
Christian Heimes9bd667a2008-01-20 15:14:11 +0000348 try:
349 if os.path.islink(path):
350 # symlinks to directories are forbidden, see bug #1669
351 raise OSError("Cannot call rmtree on a symbolic link")
352 except OSError:
353 onerror(os.path.islink, path, sys.exc_info())
354 # can't continue even if onerror hook returns
355 return
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000356 names = []
357 try:
358 names = os.listdir(path)
Éric Araujocfcc9772011-08-10 20:54:33 +0200359 except os.error:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000360 onerror(os.listdir, path, sys.exc_info())
361 for name in names:
362 fullname = os.path.join(path, name)
363 try:
364 mode = os.lstat(fullname).st_mode
365 except os.error:
366 mode = 0
367 if stat.S_ISDIR(mode):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200368 _rmtree_unsafe(fullname, onerror)
Barry Warsaw234d9a92003-01-24 17:36:15 +0000369 else:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000370 try:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200371 os.unlink(fullname)
Éric Araujocfcc9772011-08-10 20:54:33 +0200372 except os.error:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200373 onerror(os.unlink, fullname, sys.exc_info())
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000374 try:
375 os.rmdir(path)
376 except os.error:
377 onerror(os.rmdir, path, sys.exc_info())
Guido van Rossumd7673291998-02-06 21:38:09 +0000378
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200379# Version using fd-based APIs to protect against races
380def _rmtree_safe_fd(topfd, path, onerror):
381 names = []
382 try:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200383 names = os.listdir(topfd)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200384 except os.error:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200385 onerror(os.listdir, path, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200386 for name in names:
387 fullname = os.path.join(path, name)
388 try:
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200389 orig_st = os.stat(name, dir_fd=topfd, follow_symlinks=False)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200390 mode = orig_st.st_mode
391 except os.error:
392 mode = 0
393 if stat.S_ISDIR(mode):
394 try:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200395 dirfd = os.open(name, os.O_RDONLY, dir_fd=topfd)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200396 except os.error:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200397 onerror(os.open, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200398 else:
399 try:
400 if os.path.samestat(orig_st, os.fstat(dirfd)):
401 _rmtree_safe_fd(dirfd, fullname, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200402 try:
403 os.rmdir(name, dir_fd=topfd)
404 except os.error:
405 onerror(os.rmdir, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200406 finally:
407 os.close(dirfd)
408 else:
409 try:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200410 os.unlink(name, dir_fd=topfd)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200411 except os.error:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200412 onerror(os.unlink, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200413
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200414_use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
415 os.supports_dir_fd and
416 os.listdir in os.supports_fd and
417 os.stat in os.supports_follow_symlinks)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000418
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200419def rmtree(path, ignore_errors=False, onerror=None):
420 """Recursively delete a directory tree.
421
422 If ignore_errors is set, errors are ignored; otherwise, if onerror
423 is set, it is called to handle the error with arguments (func,
Hynek Schlawack2100b422012-06-23 20:28:32 +0200424 path, exc_info) where func is platform and implementation dependent;
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200425 path is the argument to that function that caused it to fail; and
426 exc_info is a tuple returned by sys.exc_info(). If ignore_errors
427 is false and onerror is None, an exception is raised.
428
429 """
430 if ignore_errors:
431 def onerror(*args):
432 pass
433 elif onerror is None:
434 def onerror(*args):
435 raise
436 if _use_fd_functions:
Hynek Schlawack3b527782012-06-25 13:27:31 +0200437 # While the unsafe rmtree works fine on bytes, the fd based does not.
438 if isinstance(path, bytes):
439 path = os.fsdecode(path)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200440 # Note: To guard against symlink races, we use the standard
441 # lstat()/open()/fstat() trick.
442 try:
443 orig_st = os.lstat(path)
444 except Exception:
445 onerror(os.lstat, path, sys.exc_info())
446 return
447 try:
448 fd = os.open(path, os.O_RDONLY)
449 except Exception:
450 onerror(os.lstat, path, sys.exc_info())
451 return
452 try:
453 if (stat.S_ISDIR(orig_st.st_mode) and
454 os.path.samestat(orig_st, os.fstat(fd))):
455 _rmtree_safe_fd(fd, path, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200456 try:
457 os.rmdir(path)
458 except os.error:
459 onerror(os.rmdir, path, sys.exc_info())
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200460 else:
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200461 raise NotADirectoryError(20,
462 "Not a directory: '{}'".format(path))
463 finally:
464 os.close(fd)
465 else:
466 return _rmtree_unsafe(path, onerror)
467
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000468# Allow introspection of whether or not the hardening against symlink
469# attacks is supported on the current platform
470rmtree.avoids_symlink_attacks = _use_fd_functions
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000471
Christian Heimesada8c3b2008-03-18 18:26:33 +0000472def _basename(path):
473 # A basename() variant which first strips the trailing slash, if present.
474 # Thus we always get the last component of the path, even for directories.
475 return os.path.basename(path.rstrip(os.path.sep))
476
477def move(src, dst):
478 """Recursively move a file or directory to another location. This is
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500479 similar to the Unix "mv" command. Return the file or directory's
480 destination.
Christian Heimesada8c3b2008-03-18 18:26:33 +0000481
482 If the destination is a directory or a symlink to a directory, the source
483 is moved inside the directory. The destination path must not already
484 exist.
485
486 If the destination already exists but is not a directory, it may be
487 overwritten depending on os.rename() semantics.
488
489 If the destination is on our current filesystem, then rename() is used.
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100490 Otherwise, src is copied to the destination and then removed. Symlinks are
491 recreated under the new name if os.rename() fails because of cross
492 filesystem renames.
493
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000494 A lot more could be done here... A look at a mv.c shows a lot of
495 the issues this implementation glosses over.
496
497 """
Christian Heimesada8c3b2008-03-18 18:26:33 +0000498 real_dst = dst
499 if os.path.isdir(dst):
Ronald Oussorenf51738b2011-05-06 10:23:04 +0200500 if _samefile(src, dst):
501 # We might be on a case insensitive filesystem,
502 # perform the rename anyway.
503 os.rename(src, dst)
504 return
505
Christian Heimesada8c3b2008-03-18 18:26:33 +0000506 real_dst = os.path.join(dst, _basename(src))
507 if os.path.exists(real_dst):
508 raise Error("Destination path '%s' already exists" % real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000509 try:
Christian Heimesada8c3b2008-03-18 18:26:33 +0000510 os.rename(src, real_dst)
Éric Araujocfcc9772011-08-10 20:54:33 +0200511 except OSError:
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100512 if os.path.islink(src):
513 linkto = os.readlink(src)
514 os.symlink(linkto, real_dst)
515 os.unlink(src)
516 elif os.path.isdir(src):
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000517 if _destinsrc(src, dst):
Collin Winterce36ad82007-08-30 01:19:48 +0000518 raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst))
Christian Heimesada8c3b2008-03-18 18:26:33 +0000519 copytree(src, real_dst, symlinks=True)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000520 rmtree(src)
521 else:
Christian Heimesada8c3b2008-03-18 18:26:33 +0000522 copy2(src, real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000523 os.unlink(src)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500524 return real_dst
Brett Cannon1c3fa182004-06-19 21:11:35 +0000525
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000526def _destinsrc(src, dst):
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +0000527 src = abspath(src)
528 dst = abspath(dst)
529 if not src.endswith(os.path.sep):
530 src += os.path.sep
531 if not dst.endswith(os.path.sep):
532 dst += os.path.sep
533 return dst.startswith(src)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000534
535def _get_gid(name):
536 """Returns a gid, given a group name."""
537 if getgrnam is None or name is None:
538 return None
539 try:
540 result = getgrnam(name)
541 except KeyError:
542 result = None
543 if result is not None:
544 return result[2]
545 return None
546
547def _get_uid(name):
548 """Returns an uid, given a user name."""
549 if getpwnam is None or name is None:
550 return None
551 try:
552 result = getpwnam(name)
553 except KeyError:
554 result = None
555 if result is not None:
556 return result[2]
557 return None
558
559def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
560 owner=None, group=None, logger=None):
561 """Create a (possibly compressed) tar file from all the files under
562 'base_dir'.
563
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000564 'compress' must be "gzip" (the default), "bzip2", or None.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000565
566 'owner' and 'group' can be used to define an owner and a group for the
567 archive that is being built. If not provided, the current owner and group
568 will be used.
569
Éric Araujo4433a5f2010-12-15 20:26:30 +0000570 The output tar file will be named 'base_name' + ".tar", possibly plus
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000571 the appropriate compression extension (".gz", or ".bz2").
Tarek Ziadé396fad72010-02-23 05:30:31 +0000572
573 Returns the output filename.
574 """
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000575 tar_compression = {'gzip': 'gz', None: ''}
576 compress_ext = {'gzip': '.gz'}
577
578 if _BZ2_SUPPORTED:
579 tar_compression['bzip2'] = 'bz2'
580 compress_ext['bzip2'] = '.bz2'
Tarek Ziadé396fad72010-02-23 05:30:31 +0000581
582 # flags for compression program, each element of list will be an argument
Éric Araujoc1b7e7f2011-09-18 23:12:30 +0200583 if compress is not None and compress not in compress_ext:
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000584 raise ValueError("bad value for 'compress', or compression format not "
585 "supported : {0}".format(compress))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000586
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000587 archive_name = base_name + '.tar' + compress_ext.get(compress, '')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000588 archive_dir = os.path.dirname(archive_name)
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000589
Tarek Ziadé396fad72010-02-23 05:30:31 +0000590 if not os.path.exists(archive_dir):
Éric Araujoac4e58e2011-01-29 20:32:11 +0000591 if logger is not None:
Éric Araujo43a7ee12011-08-19 02:55:11 +0200592 logger.info("creating %s", archive_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000593 if not dry_run:
594 os.makedirs(archive_dir)
595
Tarek Ziadé396fad72010-02-23 05:30:31 +0000596 # creating the tarball
Tarek Ziadé396fad72010-02-23 05:30:31 +0000597 if logger is not None:
598 logger.info('Creating tar archive')
599
600 uid = _get_uid(owner)
601 gid = _get_gid(group)
602
603 def _set_uid_gid(tarinfo):
604 if gid is not None:
605 tarinfo.gid = gid
606 tarinfo.gname = group
607 if uid is not None:
608 tarinfo.uid = uid
609 tarinfo.uname = owner
610 return tarinfo
611
612 if not dry_run:
613 tar = tarfile.open(archive_name, 'w|%s' % tar_compression[compress])
614 try:
615 tar.add(base_dir, filter=_set_uid_gid)
616 finally:
617 tar.close()
618
Tarek Ziadé396fad72010-02-23 05:30:31 +0000619 return archive_name
620
Tarek Ziadée2124162010-04-21 13:35:21 +0000621def _call_external_zip(base_dir, zip_filename, verbose=False, dry_run=False):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000622 # XXX see if we want to keep an external call here
623 if verbose:
624 zipoptions = "-r"
625 else:
626 zipoptions = "-rq"
627 from distutils.errors import DistutilsExecError
628 from distutils.spawn import spawn
629 try:
630 spawn(["zip", zipoptions, zip_filename, base_dir], dry_run=dry_run)
631 except DistutilsExecError:
632 # XXX really should distinguish between "couldn't find
633 # external 'zip' command" and "zip failed".
634 raise ExecError("unable to create zip file '%s': "
635 "could neither import the 'zipfile' module nor "
636 "find a standalone zip utility") % zip_filename
637
638def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None):
639 """Create a zip file from all the files under 'base_dir'.
640
Éric Araujo4433a5f2010-12-15 20:26:30 +0000641 The output zip file will be named 'base_name' + ".zip". Uses either the
Tarek Ziadé396fad72010-02-23 05:30:31 +0000642 "zipfile" Python module (if available) or the InfoZIP "zip" utility
643 (if installed and found on the default search path). If neither tool is
644 available, raises ExecError. Returns the name of the output zip
645 file.
646 """
647 zip_filename = base_name + ".zip"
648 archive_dir = os.path.dirname(base_name)
649
650 if not os.path.exists(archive_dir):
651 if logger is not None:
652 logger.info("creating %s", archive_dir)
653 if not dry_run:
654 os.makedirs(archive_dir)
655
656 # If zipfile module is not available, try spawning an external 'zip'
657 # command.
658 try:
659 import zipfile
660 except ImportError:
661 zipfile = None
662
663 if zipfile is None:
Tarek Ziadée2124162010-04-21 13:35:21 +0000664 _call_external_zip(base_dir, zip_filename, verbose, dry_run)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000665 else:
666 if logger is not None:
667 logger.info("creating '%s' and adding '%s' to it",
668 zip_filename, base_dir)
669
670 if not dry_run:
671 zip = zipfile.ZipFile(zip_filename, "w",
672 compression=zipfile.ZIP_DEFLATED)
673
674 for dirpath, dirnames, filenames in os.walk(base_dir):
675 for name in filenames:
676 path = os.path.normpath(os.path.join(dirpath, name))
677 if os.path.isfile(path):
678 zip.write(path, path)
679 if logger is not None:
680 logger.info("adding '%s'", path)
681 zip.close()
682
683 return zip_filename
684
685_ARCHIVE_FORMATS = {
686 'gztar': (_make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"),
Tarek Ziadé396fad72010-02-23 05:30:31 +0000687 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"),
Éric Araujoc1b7e7f2011-09-18 23:12:30 +0200688 'zip': (_make_zipfile, [], "ZIP file")
Tarek Ziadé396fad72010-02-23 05:30:31 +0000689 }
690
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000691if _BZ2_SUPPORTED:
692 _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')],
693 "bzip2'ed tar-file")
694
Tarek Ziadé396fad72010-02-23 05:30:31 +0000695def get_archive_formats():
696 """Returns a list of supported formats for archiving and unarchiving.
697
698 Each element of the returned sequence is a tuple (name, description)
699 """
700 formats = [(name, registry[2]) for name, registry in
701 _ARCHIVE_FORMATS.items()]
702 formats.sort()
703 return formats
704
705def register_archive_format(name, function, extra_args=None, description=''):
706 """Registers an archive format.
707
708 name is the name of the format. function is the callable that will be
709 used to create archives. If provided, extra_args is a sequence of
710 (name, value) tuples that will be passed as arguments to the callable.
711 description can be provided to describe the format, and will be returned
712 by the get_archive_formats() function.
713 """
714 if extra_args is None:
715 extra_args = []
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200716 if not callable(function):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000717 raise TypeError('The %s object is not callable' % function)
718 if not isinstance(extra_args, (tuple, list)):
719 raise TypeError('extra_args needs to be a sequence')
720 for element in extra_args:
Éric Araujoc1b7e7f2011-09-18 23:12:30 +0200721 if not isinstance(element, (tuple, list)) or len(element) !=2:
Tarek Ziadé396fad72010-02-23 05:30:31 +0000722 raise TypeError('extra_args elements are : (arg_name, value)')
723
724 _ARCHIVE_FORMATS[name] = (function, extra_args, description)
725
726def unregister_archive_format(name):
727 del _ARCHIVE_FORMATS[name]
728
729def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
730 dry_run=0, owner=None, group=None, logger=None):
731 """Create an archive file (eg. zip or tar).
732
733 'base_name' is the name of the file to create, minus any format-specific
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000734 extension; 'format' is the archive format: one of "zip", "tar", "bztar"
735 or "gztar".
Tarek Ziadé396fad72010-02-23 05:30:31 +0000736
737 'root_dir' is a directory that will be the root directory of the
738 archive; ie. we typically chdir into 'root_dir' before creating the
739 archive. 'base_dir' is the directory where we start archiving from;
740 ie. 'base_dir' will be the common prefix of all files and
741 directories in the archive. 'root_dir' and 'base_dir' both default
742 to the current directory. Returns the name of the archive file.
743
744 'owner' and 'group' are used when creating a tar archive. By default,
745 uses the current owner and group.
746 """
747 save_cwd = os.getcwd()
748 if root_dir is not None:
749 if logger is not None:
750 logger.debug("changing into '%s'", root_dir)
751 base_name = os.path.abspath(base_name)
752 if not dry_run:
753 os.chdir(root_dir)
754
755 if base_dir is None:
756 base_dir = os.curdir
757
758 kwargs = {'dry_run': dry_run, 'logger': logger}
759
760 try:
761 format_info = _ARCHIVE_FORMATS[format]
762 except KeyError:
763 raise ValueError("unknown archive format '%s'" % format)
764
765 func = format_info[0]
766 for arg, val in format_info[1]:
767 kwargs[arg] = val
768
769 if format != 'zip':
770 kwargs['owner'] = owner
771 kwargs['group'] = group
772
773 try:
774 filename = func(base_name, base_dir, **kwargs)
775 finally:
776 if root_dir is not None:
777 if logger is not None:
778 logger.debug("changing back to '%s'", save_cwd)
779 os.chdir(save_cwd)
780
781 return filename
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000782
783
784def get_unpack_formats():
785 """Returns a list of supported formats for unpacking.
786
787 Each element of the returned sequence is a tuple
788 (name, extensions, description)
789 """
790 formats = [(name, info[0], info[3]) for name, info in
791 _UNPACK_FORMATS.items()]
792 formats.sort()
793 return formats
794
795def _check_unpack_options(extensions, function, extra_args):
796 """Checks what gets registered as an unpacker."""
797 # first make sure no other unpacker is registered for this extension
798 existing_extensions = {}
799 for name, info in _UNPACK_FORMATS.items():
800 for ext in info[0]:
801 existing_extensions[ext] = name
802
803 for extension in extensions:
804 if extension in existing_extensions:
805 msg = '%s is already registered for "%s"'
806 raise RegistryError(msg % (extension,
807 existing_extensions[extension]))
808
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200809 if not callable(function):
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000810 raise TypeError('The registered function must be a callable')
811
812
813def register_unpack_format(name, extensions, function, extra_args=None,
814 description=''):
815 """Registers an unpack format.
816
817 `name` is the name of the format. `extensions` is a list of extensions
818 corresponding to the format.
819
820 `function` is the callable that will be
821 used to unpack archives. The callable will receive archives to unpack.
822 If it's unable to handle an archive, it needs to raise a ReadError
823 exception.
824
825 If provided, `extra_args` is a sequence of
826 (name, value) tuples that will be passed as arguments to the callable.
827 description can be provided to describe the format, and will be returned
828 by the get_unpack_formats() function.
829 """
830 if extra_args is None:
831 extra_args = []
832 _check_unpack_options(extensions, function, extra_args)
833 _UNPACK_FORMATS[name] = extensions, function, extra_args, description
834
835def unregister_unpack_format(name):
836 """Removes the pack format from the registery."""
837 del _UNPACK_FORMATS[name]
838
839def _ensure_directory(path):
840 """Ensure that the parent directory of `path` exists"""
841 dirname = os.path.dirname(path)
842 if not os.path.isdir(dirname):
843 os.makedirs(dirname)
844
845def _unpack_zipfile(filename, extract_dir):
846 """Unpack zip `filename` to `extract_dir`
847 """
848 try:
849 import zipfile
850 except ImportError:
851 raise ReadError('zlib not supported, cannot unpack this archive.')
852
853 if not zipfile.is_zipfile(filename):
854 raise ReadError("%s is not a zip file" % filename)
855
856 zip = zipfile.ZipFile(filename)
857 try:
858 for info in zip.infolist():
859 name = info.filename
860
861 # don't extract absolute paths or ones with .. in them
862 if name.startswith('/') or '..' in name:
863 continue
864
865 target = os.path.join(extract_dir, *name.split('/'))
866 if not target:
867 continue
868
869 _ensure_directory(target)
870 if not name.endswith('/'):
871 # file
872 data = zip.read(info.filename)
Éric Araujoc1b7e7f2011-09-18 23:12:30 +0200873 f = open(target, 'wb')
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000874 try:
875 f.write(data)
876 finally:
877 f.close()
878 del data
879 finally:
880 zip.close()
881
882def _unpack_tarfile(filename, extract_dir):
883 """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir`
884 """
885 try:
886 tarobj = tarfile.open(filename)
887 except tarfile.TarError:
888 raise ReadError(
889 "%s is not a compressed or uncompressed tar file" % filename)
890 try:
891 tarobj.extractall(extract_dir)
892 finally:
893 tarobj.close()
894
895_UNPACK_FORMATS = {
896 'gztar': (['.tar.gz', '.tgz'], _unpack_tarfile, [], "gzip'ed tar-file"),
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000897 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"),
898 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file")
899 }
900
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000901if _BZ2_SUPPORTED:
902 _UNPACK_FORMATS['bztar'] = (['.bz2'], _unpack_tarfile, [],
903 "bzip2'ed tar-file")
904
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000905def _find_unpack_format(filename):
906 for name, info in _UNPACK_FORMATS.items():
907 for extension in info[0]:
908 if filename.endswith(extension):
909 return name
910 return None
911
912def unpack_archive(filename, extract_dir=None, format=None):
913 """Unpack an archive.
914
915 `filename` is the name of the archive.
916
917 `extract_dir` is the name of the target directory, where the archive
918 is unpacked. If not provided, the current working directory is used.
919
920 `format` is the archive format: one of "zip", "tar", or "gztar". Or any
921 other registered format. If not provided, unpack_archive will use the
922 filename extension and see if an unpacker was registered for that
923 extension.
924
925 In case none is found, a ValueError is raised.
926 """
927 if extract_dir is None:
928 extract_dir = os.getcwd()
929
930 if format is not None:
931 try:
932 format_info = _UNPACK_FORMATS[format]
933 except KeyError:
934 raise ValueError("Unknown unpack format '{0}'".format(format))
935
Nick Coghlanabf202d2011-03-16 13:52:20 -0400936 func = format_info[1]
937 func(filename, extract_dir, **dict(format_info[2]))
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000938 else:
939 # we need to look at the registered unpackers supported extensions
940 format = _find_unpack_format(filename)
941 if format is None:
942 raise ReadError("Unknown archive format '{0}'".format(filename))
943
944 func = _UNPACK_FORMATS[format][1]
945 kwargs = dict(_UNPACK_FORMATS[format][2])
946 func(filename, extract_dir, **kwargs)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200947
Éric Araujoe4d5b8e2011-08-08 16:51:11 +0200948
949if hasattr(os, 'statvfs'):
950
951 __all__.append('disk_usage')
952 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200953
954 def disk_usage(path):
Éric Araujoe4d5b8e2011-08-08 16:51:11 +0200955 """Return disk usage statistics about the given path.
956
Sandro Tosif8ae4fa2012-04-23 20:07:15 +0200957 Returned value is a named tuple with attributes 'total', 'used' and
Éric Araujoe4d5b8e2011-08-08 16:51:11 +0200958 'free', which are the amount of total, used and free space, in bytes.
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200959 """
Éric Araujoe4d5b8e2011-08-08 16:51:11 +0200960 st = os.statvfs(path)
961 free = st.f_bavail * st.f_frsize
962 total = st.f_blocks * st.f_frsize
963 used = (st.f_blocks - st.f_bfree) * st.f_frsize
964 return _ntuple_diskusage(total, used, free)
965
966elif os.name == 'nt':
967
968 import nt
969 __all__.append('disk_usage')
970 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
971
972 def disk_usage(path):
973 """Return disk usage statistics about the given path.
974
975 Returned valus is a named tuple with attributes 'total', 'used' and
976 'free', which are the amount of total, used and free space, in bytes.
977 """
978 total, free = nt._getdiskusage(path)
979 used = total - free
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200980 return _ntuple_diskusage(total, used, free)
Sandro Tosid902a142011-08-22 23:28:27 +0200981
Éric Araujo0ac4a5d2011-09-01 08:31:51 +0200982
Sandro Tosid902a142011-08-22 23:28:27 +0200983def chown(path, user=None, group=None):
984 """Change owner user and group of the given path.
985
986 user and group can be the uid/gid or the user/group names, and in that case,
987 they are converted to their respective uid/gid.
988 """
989
990 if user is None and group is None:
991 raise ValueError("user and/or group must be set")
992
993 _user = user
994 _group = group
995
996 # -1 means don't change it
997 if user is None:
998 _user = -1
999 # user can either be an int (the uid) or a string (the system username)
1000 elif isinstance(user, str):
1001 _user = _get_uid(user)
1002 if _user is None:
1003 raise LookupError("no such user: {!r}".format(user))
1004
1005 if group is None:
1006 _group = -1
1007 elif not isinstance(group, int):
1008 _group = _get_gid(group)
1009 if _group is None:
1010 raise LookupError("no such group: {!r}".format(group))
1011
1012 os.chown(path, _user, _group)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001013
1014def get_terminal_size(fallback=(80, 24)):
1015 """Get the size of the terminal window.
1016
1017 For each of the two dimensions, the environment variable, COLUMNS
1018 and LINES respectively, is checked. If the variable is defined and
1019 the value is a positive integer, it is used.
1020
1021 When COLUMNS or LINES is not defined, which is the common case,
1022 the terminal connected to sys.__stdout__ is queried
1023 by invoking os.get_terminal_size.
1024
1025 If the terminal size cannot be successfully queried, either because
1026 the system doesn't support querying, or because we are not
1027 connected to a terminal, the value given in fallback parameter
1028 is used. Fallback defaults to (80, 24) which is the default
1029 size used by many terminal emulators.
1030
1031 The value returned is a named tuple of type os.terminal_size.
1032 """
1033 # columns, lines are the working values
1034 try:
1035 columns = int(os.environ['COLUMNS'])
1036 except (KeyError, ValueError):
1037 columns = 0
1038
1039 try:
1040 lines = int(os.environ['LINES'])
1041 except (KeyError, ValueError):
1042 lines = 0
1043
1044 # only query if necessary
1045 if columns <= 0 or lines <= 0:
1046 try:
1047 size = os.get_terminal_size(sys.__stdout__.fileno())
1048 except (NameError, OSError):
1049 size = os.terminal_size(fallback)
1050 if columns <= 0:
1051 columns = size.columns
1052 if lines <= 0:
1053 lines = size.lines
1054
1055 return os.terminal_size((columns, lines))
Brian Curtinc57a3452012-06-22 16:00:30 -05001056
1057def which(cmd, mode=os.F_OK | os.X_OK, path=None):
Brian Curtindc00f1e2012-06-22 22:49:12 -05001058 """Given a command, mode, and a PATH string, return the path which
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001059 conforms to the given mode on the PATH, or None if there is no such
1060 file.
1061
1062 `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
1063 of os.environ.get("PATH"), or can be overridden with a custom search
1064 path.
1065
1066 """
Brian Curtinc57a3452012-06-22 16:00:30 -05001067 # Check that a given file can be accessed with the correct mode.
1068 # Additionally check that `file` is not a directory, as on Windows
1069 # directories pass the os.access check.
1070 def _access_check(fn, mode):
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001071 return (os.path.exists(fn) and os.access(fn, mode)
1072 and not os.path.isdir(fn))
Brian Curtinc57a3452012-06-22 16:00:30 -05001073
1074 # Short circuit. If we're given a full path which matches the mode
1075 # and it exists, we're done here.
1076 if _access_check(cmd, mode):
1077 return cmd
1078
1079 path = (path or os.environ.get("PATH", os.defpath)).split(os.pathsep)
1080
1081 if sys.platform == "win32":
1082 # The current directory takes precedence on Windows.
1083 if not os.curdir in path:
1084 path.insert(0, os.curdir)
1085
1086 # PATHEXT is necessary to check on Windows.
1087 pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
1088 # See if the given file matches any of the expected path extensions.
1089 # This will allow us to short circuit when given "python.exe".
1090 matches = [cmd for ext in pathext if cmd.lower().endswith(ext.lower())]
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001091 # If it does match, only test that one, otherwise we have to try
1092 # others.
1093 files = [cmd] if matches else [cmd + ext.lower() for ext in pathext]
Brian Curtinc57a3452012-06-22 16:00:30 -05001094 else:
1095 # On other platforms you don't have things like PATHEXT to tell you
1096 # what file suffixes are executable, so just pass on cmd as-is.
1097 files = [cmd]
1098
1099 seen = set()
1100 for dir in path:
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001101 dir = os.path.normcase(dir)
Brian Curtinc57a3452012-06-22 16:00:30 -05001102 if not dir in seen:
1103 seen.add(dir)
1104 for thefile in files:
1105 name = os.path.join(dir, thefile)
1106 if _access_check(name, mode):
1107 return name
1108 return None