blob: 99e4017d860da229ab291831fe945a120a3503eb [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
Antoine Pitrou7fff0962009-05-01 21:09:44 +000045class SpecialFileError(EnvironmentError):
46 """Raised when trying to do a kind of operation (e.g. copying) which is
47 not supported on a special file (e.g. a named pipe)"""
48
Tarek Ziadé396fad72010-02-23 05:30:31 +000049class ExecError(EnvironmentError):
50 """Raised when a command could not be executed"""
51
Tarek Ziadé6ac91722010-04-28 17:51:36 +000052class ReadError(EnvironmentError):
53 """Raised when an archive cannot be read"""
54
55class RegistryError(Exception):
56 """Raised when a registery operation with the archiving
57 and unpacking registeries fails"""
58
59
Georg Brandl6aa2d1f2008-08-12 08:35:52 +000060try:
61 WindowsError
62except NameError:
63 WindowsError = None
64
Greg Stein42bb8b32000-07-12 09:55:30 +000065def copyfileobj(fsrc, fdst, length=16*1024):
66 """copy data from file-like object fsrc to file-like object fdst"""
67 while 1:
68 buf = fsrc.read(length)
69 if not buf:
70 break
71 fdst.write(buf)
72
Johannes Gijsbers46f14592004-08-14 13:30:02 +000073def _samefile(src, dst):
74 # Macintosh, Unix.
Tarek Ziadé1eab9cc2010-04-19 21:19:57 +000075 if hasattr(os.path, 'samefile'):
Johannes Gijsbersf9a098e2004-08-14 14:51:01 +000076 try:
77 return os.path.samefile(src, dst)
78 except OSError:
79 return False
Johannes Gijsbers46f14592004-08-14 13:30:02 +000080
81 # All other platforms: check for same pathname.
82 return (os.path.normcase(os.path.abspath(src)) ==
83 os.path.normcase(os.path.abspath(dst)))
Tim Peters495ad3c2001-01-15 01:36:40 +000084
Antoine Pitrou78091e62011-12-29 18:54:15 +010085def copyfile(src, dst, symlinks=False):
86 """Copy data from src to dst.
87
88 If optional flag `symlinks` is set and `src` is a symbolic link, a new
89 symlink will be created instead of copying the file it points to.
90
91 """
Johannes Gijsbers46f14592004-08-14 13:30:02 +000092 if _samefile(src, dst):
Collin Winterce36ad82007-08-30 01:19:48 +000093 raise Error("`%s` and `%s` are the same file" % (src, dst))
Johannes Gijsbers46f14592004-08-14 13:30:02 +000094
Antoine Pitrou7fff0962009-05-01 21:09:44 +000095 for fn in [src, dst]:
96 try:
97 st = os.stat(fn)
98 except OSError:
99 # File most likely does not exist
100 pass
Benjamin Petersonc0d98aa2009-06-05 19:13:27 +0000101 else:
102 # XXX What about other special files? (sockets, devices...)
103 if stat.S_ISFIFO(st.st_mode):
104 raise SpecialFileError("`%s` is a named pipe" % fn)
Tarek Ziadéb01142b2010-05-05 22:43:04 +0000105
Antoine Pitrou78091e62011-12-29 18:54:15 +0100106 if symlinks and os.path.islink(src):
107 os.symlink(os.readlink(src), dst)
108 else:
109 with open(src, 'rb') as fsrc:
110 with open(dst, 'wb') as fdst:
111 copyfileobj(fsrc, fdst)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500112 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000113
Antoine Pitrou78091e62011-12-29 18:54:15 +0100114def copymode(src, dst, symlinks=False):
115 """Copy mode bits from src to dst.
Guido van Rossumc6360141990-10-13 19:23:40 +0000116
Antoine Pitrou78091e62011-12-29 18:54:15 +0100117 If the optional flag `symlinks` is set, symlinks aren't followed if and
118 only if both `src` and `dst` are symlinks. If `lchmod` isn't available (eg.
119 Linux), in these cases, this method does nothing.
120
121 """
122 if symlinks and os.path.islink(src) and os.path.islink(dst):
123 if hasattr(os, 'lchmod'):
124 stat_func, chmod_func = os.lstat, os.lchmod
125 else:
126 return
127 elif hasattr(os, 'chmod'):
128 stat_func, chmod_func = os.stat, os.chmod
129 else:
130 return
131
132 st = stat_func(src)
133 chmod_func(dst, stat.S_IMODE(st.st_mode))
134
135def copystat(src, dst, symlinks=False):
136 """Copy all stat info (mode bits, atime, mtime, flags) from src to dst.
137
138 If the optional flag `symlinks` is set, symlinks aren't followed if and
139 only if both `src` and `dst` are symlinks.
140
141 """
Larry Hastings9cf065c2012-06-22 16:30:09 -0700142 def _nop(*args, ns=None, follow_symlinks=None):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100143 pass
144
Larry Hastings9cf065c2012-06-22 16:30:09 -0700145 # follow symlinks (aka don't not follow symlinks)
146 follow = not (symlinks and os.path.islink(src) and os.path.islink(dst))
147 if follow:
148 # use the real function if it exists
149 def lookup(name):
150 return getattr(os, name, _nop)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100151 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700152 # use the real function only if it exists
153 # *and* it supports follow_symlinks
154 def lookup(name):
155 fn = getattr(os, name, _nop)
156 if fn in os.supports_follow_symlinks:
157 return fn
158 return _nop
Antoine Pitrou78091e62011-12-29 18:54:15 +0100159
Larry Hastings9cf065c2012-06-22 16:30:09 -0700160 st = lookup("stat")(src, follow_symlinks=follow)
Walter Dörwald294bbf32002-06-06 09:48:13 +0000161 mode = stat.S_IMODE(st.st_mode)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700162 lookup("utime")(dst, ns=(st.st_atime_ns, st.st_mtime_ns),
163 follow_symlinks=follow)
164 try:
165 lookup("chmod")(dst, mode, follow_symlinks=follow)
166 except NotImplementedError:
167 # if we got a NotImplementedError, it's because
168 # * follow_symlinks=False,
169 # * lchown() is unavailable, and
170 # * either
171 # * fchownat() is unvailable or
172 # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW.
173 # (it returned ENOSUP.)
174 # therefore we're out of options--we simply cannot chown the
175 # symlink. give up, suppress the error.
176 # (which is what shutil always did in this circumstance.)
177 pass
Antoine Pitrou78091e62011-12-29 18:54:15 +0100178 if hasattr(st, 'st_flags'):
Antoine Pitrou910bd512010-03-22 20:11:09 +0000179 try:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700180 lookup("chflags")(dst, st.st_flags, follow_symlinks=follow)
Antoine Pitrou910bd512010-03-22 20:11:09 +0000181 except OSError as why:
Ned Deilybaf75712012-05-10 17:05:19 -0700182 for err in 'EOPNOTSUPP', 'ENOTSUP':
183 if hasattr(errno, err) and why.errno == getattr(errno, err):
184 break
185 else:
Antoine Pitrou910bd512010-03-22 20:11:09 +0000186 raise
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000187
Antoine Pitrou424246f2012-05-12 19:02:01 +0200188if hasattr(os, 'listxattr'):
189 def _copyxattr(src, dst, symlinks=False):
190 """Copy extended filesystem attributes from `src` to `dst`.
191
192 Overwrite existing attributes.
193
194 If the optional flag `symlinks` is set, symlinks won't be followed.
195
196 """
Antoine Pitrou424246f2012-05-12 19:02:01 +0200197
Larry Hastings9cf065c2012-06-22 16:30:09 -0700198 for name in os.listxattr(src, follow_symlinks=symlinks):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200199 try:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700200 value = os.getxattr(src, name, follow_symlinks=symlinks)
201 os.setxattr(dst, name, value, follow_symlinks=symlinks)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200202 except OSError as e:
203 if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA):
204 raise
205else:
206 def _copyxattr(*args, **kwargs):
207 pass
208
Antoine Pitrou78091e62011-12-29 18:54:15 +0100209def copy(src, dst, symlinks=False):
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500210 """Copy data and mode bits ("cp src dst"). Return the file's destination.
Tim Peters495ad3c2001-01-15 01:36:40 +0000211
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000212 The destination may be a directory.
213
Antoine Pitrou78091e62011-12-29 18:54:15 +0100214 If the optional flag `symlinks` is set, symlinks won't be followed. This
215 resembles GNU's "cp -P src dst".
216
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000217 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000218 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000219 dst = os.path.join(dst, os.path.basename(src))
Antoine Pitrou78091e62011-12-29 18:54:15 +0100220 copyfile(src, dst, symlinks=symlinks)
221 copymode(src, dst, symlinks=symlinks)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500222 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000223
Antoine Pitrou78091e62011-12-29 18:54:15 +0100224def copy2(src, dst, symlinks=False):
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500225 """Copy data and all stat info ("cp -p src dst"). Return the file's
226 destination."
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000227
228 The destination may be a directory.
229
Antoine Pitrou78091e62011-12-29 18:54:15 +0100230 If the optional flag `symlinks` is set, symlinks won't be followed. This
231 resembles GNU's "cp -P src dst".
232
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000233 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000234 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000235 dst = os.path.join(dst, os.path.basename(src))
Antoine Pitrou78091e62011-12-29 18:54:15 +0100236 copyfile(src, dst, symlinks=symlinks)
237 copystat(src, dst, symlinks=symlinks)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200238 _copyxattr(src, dst, symlinks=symlinks)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500239 return dst
Guido van Rossumc6360141990-10-13 19:23:40 +0000240
Georg Brandl2ee470f2008-07-16 12:55:28 +0000241def ignore_patterns(*patterns):
242 """Function that can be used as copytree() ignore parameter.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000243
Georg Brandl2ee470f2008-07-16 12:55:28 +0000244 Patterns is a sequence of glob-style patterns
245 that are used to exclude files"""
246 def _ignore_patterns(path, names):
247 ignored_names = []
248 for pattern in patterns:
249 ignored_names.extend(fnmatch.filter(names, pattern))
250 return set(ignored_names)
251 return _ignore_patterns
252
Tarek Ziadéfb437512010-04-20 08:57:33 +0000253def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
254 ignore_dangling_symlinks=False):
Tarek Ziadé5340db32010-04-19 22:30:51 +0000255 """Recursively copy a directory tree.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000256
257 The destination directory must not already exist.
Neal Norwitza4c93b62003-02-23 21:36:32 +0000258 If exception(s) occur, an Error is raised with a list of reasons.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000259
260 If the optional symlinks flag is true, symbolic links in the
261 source tree result in symbolic links in the destination tree; if
262 it is false, the contents of the files pointed to by symbolic
Tarek Ziadéfb437512010-04-20 08:57:33 +0000263 links are copied. If the file pointed by the symlink doesn't
264 exist, an exception will be added in the list of errors raised in
265 an Error exception at the end of the copy process.
266
267 You can set the optional ignore_dangling_symlinks flag to true if you
Tarek Ziadé8c26c7d2010-04-23 13:03:50 +0000268 want to silence this exception. Notice that this has no effect on
269 platforms that don't support os.symlink.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000270
Georg Brandl2ee470f2008-07-16 12:55:28 +0000271 The optional ignore argument is a callable. If given, it
272 is called with the `src` parameter, which is the directory
273 being visited by copytree(), and `names` which is the list of
274 `src` contents, as returned by os.listdir():
275
276 callable(src, names) -> ignored_names
277
278 Since copytree() is called recursively, the callable will be
279 called once for each directory that is copied. It returns a
280 list of names relative to the `src` directory that should
281 not be copied.
282
Tarek Ziadé5340db32010-04-19 22:30:51 +0000283 The optional copy_function argument is a callable that will be used
284 to copy each file. It will be called with the source path and the
285 destination path as arguments. By default, copy2() is used, but any
286 function that supports the same signature (like copy()) can be used.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000287
288 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000289 names = os.listdir(src)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000290 if ignore is not None:
291 ignored_names = ignore(src, names)
292 else:
293 ignored_names = set()
294
Johannes Gijsberse4172ea2005-01-08 12:31:29 +0000295 os.makedirs(dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000296 errors = []
Guido van Rossuma2baf461997-04-29 14:06:46 +0000297 for name in names:
Georg Brandl2ee470f2008-07-16 12:55:28 +0000298 if name in ignored_names:
299 continue
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000300 srcname = os.path.join(src, name)
301 dstname = os.path.join(dst, name)
302 try:
Tarek Ziadéfb437512010-04-20 08:57:33 +0000303 if os.path.islink(srcname):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000304 linkto = os.readlink(srcname)
Tarek Ziadéfb437512010-04-20 08:57:33 +0000305 if symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100306 # We can't just leave it to `copy_function` because legacy
307 # code with a custom `copy_function` may rely on copytree
308 # doing the right thing.
Tarek Ziadéfb437512010-04-20 08:57:33 +0000309 os.symlink(linkto, dstname)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100310 copystat(srcname, dstname, symlinks=symlinks)
Tarek Ziadéfb437512010-04-20 08:57:33 +0000311 else:
312 # ignore dangling symlink if the flag is on
313 if not os.path.exists(linkto) and ignore_dangling_symlinks:
314 continue
315 # otherwise let the copy occurs. copy2 will raise an error
316 copy_function(srcname, dstname)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000317 elif os.path.isdir(srcname):
Tarek Ziadé5340db32010-04-19 22:30:51 +0000318 copytree(srcname, dstname, symlinks, ignore, copy_function)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000319 else:
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000320 # Will raise a SpecialFileError for unsupported file types
Tarek Ziadé5340db32010-04-19 22:30:51 +0000321 copy_function(srcname, dstname)
Georg Brandla1be88e2005-08-31 22:48:45 +0000322 # catch the Error from the recursive copytree so that we can
323 # continue with other files
Guido van Rossumb940e112007-01-10 16:19:56 +0000324 except Error as err:
Georg Brandla1be88e2005-08-31 22:48:45 +0000325 errors.extend(err.args[0])
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000326 except EnvironmentError as why:
327 errors.append((srcname, dstname, str(why)))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000328 try:
329 copystat(src, dst)
Guido van Rossumb940e112007-01-10 16:19:56 +0000330 except OSError as why:
Georg Brandl6aa2d1f2008-08-12 08:35:52 +0000331 if WindowsError is not None and isinstance(why, WindowsError):
332 # Copying file access times may fail on Windows
333 pass
334 else:
335 errors.extend((src, dst, str(why)))
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000336 if errors:
Collin Winterce36ad82007-08-30 01:19:48 +0000337 raise Error(errors)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500338 return dst
Guido van Rossumd7673291998-02-06 21:38:09 +0000339
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200340# version vulnerable to race conditions
341def _rmtree_unsafe(path, onerror):
Christian Heimes9bd667a2008-01-20 15:14:11 +0000342 try:
343 if os.path.islink(path):
344 # symlinks to directories are forbidden, see bug #1669
345 raise OSError("Cannot call rmtree on a symbolic link")
346 except OSError:
347 onerror(os.path.islink, path, sys.exc_info())
348 # can't continue even if onerror hook returns
349 return
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000350 names = []
351 try:
352 names = os.listdir(path)
Éric Araujocfcc9772011-08-10 20:54:33 +0200353 except os.error:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000354 onerror(os.listdir, path, sys.exc_info())
355 for name in names:
356 fullname = os.path.join(path, name)
357 try:
358 mode = os.lstat(fullname).st_mode
359 except os.error:
360 mode = 0
361 if stat.S_ISDIR(mode):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200362 _rmtree_unsafe(fullname, onerror)
Barry Warsaw234d9a92003-01-24 17:36:15 +0000363 else:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000364 try:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200365 os.unlink(fullname)
Éric Araujocfcc9772011-08-10 20:54:33 +0200366 except os.error:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200367 onerror(os.unlink, fullname, sys.exc_info())
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000368 try:
369 os.rmdir(path)
370 except os.error:
371 onerror(os.rmdir, path, sys.exc_info())
Guido van Rossumd7673291998-02-06 21:38:09 +0000372
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200373# Version using fd-based APIs to protect against races
374def _rmtree_safe_fd(topfd, path, onerror):
375 names = []
376 try:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200377 names = os.listdir(topfd)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200378 except os.error:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200379 onerror(os.listdir, path, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200380 for name in names:
381 fullname = os.path.join(path, name)
382 try:
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200383 orig_st = os.stat(name, dir_fd=topfd, follow_symlinks=False)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200384 mode = orig_st.st_mode
385 except os.error:
386 mode = 0
387 if stat.S_ISDIR(mode):
388 try:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200389 dirfd = os.open(name, os.O_RDONLY, dir_fd=topfd)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200390 except os.error:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200391 onerror(os.open, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200392 else:
393 try:
394 if os.path.samestat(orig_st, os.fstat(dirfd)):
395 _rmtree_safe_fd(dirfd, fullname, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200396 try:
397 os.rmdir(name, dir_fd=topfd)
398 except os.error:
399 onerror(os.rmdir, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200400 finally:
401 os.close(dirfd)
402 else:
403 try:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200404 os.unlink(name, dir_fd=topfd)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200405 except os.error:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200406 onerror(os.unlink, fullname, sys.exc_info())
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200407
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000408_use_fd_functions = (os.unlink in os.supports_dir_fd and
409 os.open in os.supports_dir_fd)
410
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200411def rmtree(path, ignore_errors=False, onerror=None):
412 """Recursively delete a directory tree.
413
414 If ignore_errors is set, errors are ignored; otherwise, if onerror
415 is set, it is called to handle the error with arguments (func,
Hynek Schlawack2100b422012-06-23 20:28:32 +0200416 path, exc_info) where func is platform and implementation dependent;
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200417 path is the argument to that function that caused it to fail; and
418 exc_info is a tuple returned by sys.exc_info(). If ignore_errors
419 is false and onerror is None, an exception is raised.
420
421 """
422 if ignore_errors:
423 def onerror(*args):
424 pass
425 elif onerror is None:
426 def onerror(*args):
427 raise
428 if _use_fd_functions:
Hynek Schlawack3b527782012-06-25 13:27:31 +0200429 # While the unsafe rmtree works fine on bytes, the fd based does not.
430 if isinstance(path, bytes):
431 path = os.fsdecode(path)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200432 # Note: To guard against symlink races, we use the standard
433 # lstat()/open()/fstat() trick.
434 try:
435 orig_st = os.lstat(path)
436 except Exception:
437 onerror(os.lstat, path, sys.exc_info())
438 return
439 try:
440 fd = os.open(path, os.O_RDONLY)
441 except Exception:
442 onerror(os.lstat, path, sys.exc_info())
443 return
444 try:
445 if (stat.S_ISDIR(orig_st.st_mode) and
446 os.path.samestat(orig_st, os.fstat(fd))):
447 _rmtree_safe_fd(fd, path, onerror)
Hynek Schlawack9f558cc2012-06-28 15:30:47 +0200448 try:
449 os.rmdir(path)
450 except os.error:
451 onerror(os.rmdir, path, sys.exc_info())
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200452 else:
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200453 raise NotADirectoryError(20,
454 "Not a directory: '{}'".format(path))
455 finally:
456 os.close(fd)
457 else:
458 return _rmtree_unsafe(path, onerror)
459
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000460# Allow introspection of whether or not the hardening against symlink
461# attacks is supported on the current platform
462rmtree.avoids_symlink_attacks = _use_fd_functions
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000463
Christian Heimesada8c3b2008-03-18 18:26:33 +0000464def _basename(path):
465 # A basename() variant which first strips the trailing slash, if present.
466 # Thus we always get the last component of the path, even for directories.
467 return os.path.basename(path.rstrip(os.path.sep))
468
469def move(src, dst):
470 """Recursively move a file or directory to another location. This is
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500471 similar to the Unix "mv" command. Return the file or directory's
472 destination.
Christian Heimesada8c3b2008-03-18 18:26:33 +0000473
474 If the destination is a directory or a symlink to a directory, the source
475 is moved inside the directory. The destination path must not already
476 exist.
477
478 If the destination already exists but is not a directory, it may be
479 overwritten depending on os.rename() semantics.
480
481 If the destination is on our current filesystem, then rename() is used.
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100482 Otherwise, src is copied to the destination and then removed. Symlinks are
483 recreated under the new name if os.rename() fails because of cross
484 filesystem renames.
485
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000486 A lot more could be done here... A look at a mv.c shows a lot of
487 the issues this implementation glosses over.
488
489 """
Christian Heimesada8c3b2008-03-18 18:26:33 +0000490 real_dst = dst
491 if os.path.isdir(dst):
Ronald Oussorenf51738b2011-05-06 10:23:04 +0200492 if _samefile(src, dst):
493 # We might be on a case insensitive filesystem,
494 # perform the rename anyway.
495 os.rename(src, dst)
496 return
497
Christian Heimesada8c3b2008-03-18 18:26:33 +0000498 real_dst = os.path.join(dst, _basename(src))
499 if os.path.exists(real_dst):
500 raise Error("Destination path '%s' already exists" % real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000501 try:
Christian Heimesada8c3b2008-03-18 18:26:33 +0000502 os.rename(src, real_dst)
Éric Araujocfcc9772011-08-10 20:54:33 +0200503 except OSError:
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100504 if os.path.islink(src):
505 linkto = os.readlink(src)
506 os.symlink(linkto, real_dst)
507 os.unlink(src)
508 elif os.path.isdir(src):
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000509 if _destinsrc(src, dst):
Collin Winterce36ad82007-08-30 01:19:48 +0000510 raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst))
Christian Heimesada8c3b2008-03-18 18:26:33 +0000511 copytree(src, real_dst, symlinks=True)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000512 rmtree(src)
513 else:
Christian Heimesada8c3b2008-03-18 18:26:33 +0000514 copy2(src, real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000515 os.unlink(src)
Brian Curtin0d0a1de2012-06-18 18:41:07 -0500516 return real_dst
Brett Cannon1c3fa182004-06-19 21:11:35 +0000517
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000518def _destinsrc(src, dst):
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +0000519 src = abspath(src)
520 dst = abspath(dst)
521 if not src.endswith(os.path.sep):
522 src += os.path.sep
523 if not dst.endswith(os.path.sep):
524 dst += os.path.sep
525 return dst.startswith(src)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000526
527def _get_gid(name):
528 """Returns a gid, given a group name."""
529 if getgrnam is None or name is None:
530 return None
531 try:
532 result = getgrnam(name)
533 except KeyError:
534 result = None
535 if result is not None:
536 return result[2]
537 return None
538
539def _get_uid(name):
540 """Returns an uid, given a user name."""
541 if getpwnam is None or name is None:
542 return None
543 try:
544 result = getpwnam(name)
545 except KeyError:
546 result = None
547 if result is not None:
548 return result[2]
549 return None
550
551def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
552 owner=None, group=None, logger=None):
553 """Create a (possibly compressed) tar file from all the files under
554 'base_dir'.
555
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000556 'compress' must be "gzip" (the default), "bzip2", or None.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000557
558 'owner' and 'group' can be used to define an owner and a group for the
559 archive that is being built. If not provided, the current owner and group
560 will be used.
561
Éric Araujo4433a5f2010-12-15 20:26:30 +0000562 The output tar file will be named 'base_name' + ".tar", possibly plus
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000563 the appropriate compression extension (".gz", or ".bz2").
Tarek Ziadé396fad72010-02-23 05:30:31 +0000564
565 Returns the output filename.
566 """
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000567 tar_compression = {'gzip': 'gz', None: ''}
568 compress_ext = {'gzip': '.gz'}
569
570 if _BZ2_SUPPORTED:
571 tar_compression['bzip2'] = 'bz2'
572 compress_ext['bzip2'] = '.bz2'
Tarek Ziadé396fad72010-02-23 05:30:31 +0000573
574 # flags for compression program, each element of list will be an argument
Éric Araujoc1b7e7f2011-09-18 23:12:30 +0200575 if compress is not None and compress not in compress_ext:
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000576 raise ValueError("bad value for 'compress', or compression format not "
577 "supported : {0}".format(compress))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000578
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000579 archive_name = base_name + '.tar' + compress_ext.get(compress, '')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000580 archive_dir = os.path.dirname(archive_name)
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000581
Tarek Ziadé396fad72010-02-23 05:30:31 +0000582 if not os.path.exists(archive_dir):
Éric Araujoac4e58e2011-01-29 20:32:11 +0000583 if logger is not None:
Éric Araujo43a7ee12011-08-19 02:55:11 +0200584 logger.info("creating %s", archive_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000585 if not dry_run:
586 os.makedirs(archive_dir)
587
Tarek Ziadé396fad72010-02-23 05:30:31 +0000588 # creating the tarball
Tarek Ziadé396fad72010-02-23 05:30:31 +0000589 if logger is not None:
590 logger.info('Creating tar archive')
591
592 uid = _get_uid(owner)
593 gid = _get_gid(group)
594
595 def _set_uid_gid(tarinfo):
596 if gid is not None:
597 tarinfo.gid = gid
598 tarinfo.gname = group
599 if uid is not None:
600 tarinfo.uid = uid
601 tarinfo.uname = owner
602 return tarinfo
603
604 if not dry_run:
605 tar = tarfile.open(archive_name, 'w|%s' % tar_compression[compress])
606 try:
607 tar.add(base_dir, filter=_set_uid_gid)
608 finally:
609 tar.close()
610
Tarek Ziadé396fad72010-02-23 05:30:31 +0000611 return archive_name
612
Tarek Ziadée2124162010-04-21 13:35:21 +0000613def _call_external_zip(base_dir, zip_filename, verbose=False, dry_run=False):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000614 # XXX see if we want to keep an external call here
615 if verbose:
616 zipoptions = "-r"
617 else:
618 zipoptions = "-rq"
619 from distutils.errors import DistutilsExecError
620 from distutils.spawn import spawn
621 try:
622 spawn(["zip", zipoptions, zip_filename, base_dir], dry_run=dry_run)
623 except DistutilsExecError:
624 # XXX really should distinguish between "couldn't find
625 # external 'zip' command" and "zip failed".
626 raise ExecError("unable to create zip file '%s': "
627 "could neither import the 'zipfile' module nor "
628 "find a standalone zip utility") % zip_filename
629
630def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None):
631 """Create a zip file from all the files under 'base_dir'.
632
Éric Araujo4433a5f2010-12-15 20:26:30 +0000633 The output zip file will be named 'base_name' + ".zip". Uses either the
Tarek Ziadé396fad72010-02-23 05:30:31 +0000634 "zipfile" Python module (if available) or the InfoZIP "zip" utility
635 (if installed and found on the default search path). If neither tool is
636 available, raises ExecError. Returns the name of the output zip
637 file.
638 """
639 zip_filename = base_name + ".zip"
640 archive_dir = os.path.dirname(base_name)
641
642 if not os.path.exists(archive_dir):
643 if logger is not None:
644 logger.info("creating %s", archive_dir)
645 if not dry_run:
646 os.makedirs(archive_dir)
647
648 # If zipfile module is not available, try spawning an external 'zip'
649 # command.
650 try:
651 import zipfile
652 except ImportError:
653 zipfile = None
654
655 if zipfile is None:
Tarek Ziadée2124162010-04-21 13:35:21 +0000656 _call_external_zip(base_dir, zip_filename, verbose, dry_run)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000657 else:
658 if logger is not None:
659 logger.info("creating '%s' and adding '%s' to it",
660 zip_filename, base_dir)
661
662 if not dry_run:
663 zip = zipfile.ZipFile(zip_filename, "w",
664 compression=zipfile.ZIP_DEFLATED)
665
666 for dirpath, dirnames, filenames in os.walk(base_dir):
667 for name in filenames:
668 path = os.path.normpath(os.path.join(dirpath, name))
669 if os.path.isfile(path):
670 zip.write(path, path)
671 if logger is not None:
672 logger.info("adding '%s'", path)
673 zip.close()
674
675 return zip_filename
676
677_ARCHIVE_FORMATS = {
678 'gztar': (_make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"),
Tarek Ziadé396fad72010-02-23 05:30:31 +0000679 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"),
Éric Araujoc1b7e7f2011-09-18 23:12:30 +0200680 'zip': (_make_zipfile, [], "ZIP file")
Tarek Ziadé396fad72010-02-23 05:30:31 +0000681 }
682
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000683if _BZ2_SUPPORTED:
684 _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')],
685 "bzip2'ed tar-file")
686
Tarek Ziadé396fad72010-02-23 05:30:31 +0000687def get_archive_formats():
688 """Returns a list of supported formats for archiving and unarchiving.
689
690 Each element of the returned sequence is a tuple (name, description)
691 """
692 formats = [(name, registry[2]) for name, registry in
693 _ARCHIVE_FORMATS.items()]
694 formats.sort()
695 return formats
696
697def register_archive_format(name, function, extra_args=None, description=''):
698 """Registers an archive format.
699
700 name is the name of the format. function is the callable that will be
701 used to create archives. If provided, extra_args is a sequence of
702 (name, value) tuples that will be passed as arguments to the callable.
703 description can be provided to describe the format, and will be returned
704 by the get_archive_formats() function.
705 """
706 if extra_args is None:
707 extra_args = []
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200708 if not callable(function):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000709 raise TypeError('The %s object is not callable' % function)
710 if not isinstance(extra_args, (tuple, list)):
711 raise TypeError('extra_args needs to be a sequence')
712 for element in extra_args:
Éric Araujoc1b7e7f2011-09-18 23:12:30 +0200713 if not isinstance(element, (tuple, list)) or len(element) !=2:
Tarek Ziadé396fad72010-02-23 05:30:31 +0000714 raise TypeError('extra_args elements are : (arg_name, value)')
715
716 _ARCHIVE_FORMATS[name] = (function, extra_args, description)
717
718def unregister_archive_format(name):
719 del _ARCHIVE_FORMATS[name]
720
721def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
722 dry_run=0, owner=None, group=None, logger=None):
723 """Create an archive file (eg. zip or tar).
724
725 'base_name' is the name of the file to create, minus any format-specific
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000726 extension; 'format' is the archive format: one of "zip", "tar", "bztar"
727 or "gztar".
Tarek Ziadé396fad72010-02-23 05:30:31 +0000728
729 'root_dir' is a directory that will be the root directory of the
730 archive; ie. we typically chdir into 'root_dir' before creating the
731 archive. 'base_dir' is the directory where we start archiving from;
732 ie. 'base_dir' will be the common prefix of all files and
733 directories in the archive. 'root_dir' and 'base_dir' both default
734 to the current directory. Returns the name of the archive file.
735
736 'owner' and 'group' are used when creating a tar archive. By default,
737 uses the current owner and group.
738 """
739 save_cwd = os.getcwd()
740 if root_dir is not None:
741 if logger is not None:
742 logger.debug("changing into '%s'", root_dir)
743 base_name = os.path.abspath(base_name)
744 if not dry_run:
745 os.chdir(root_dir)
746
747 if base_dir is None:
748 base_dir = os.curdir
749
750 kwargs = {'dry_run': dry_run, 'logger': logger}
751
752 try:
753 format_info = _ARCHIVE_FORMATS[format]
754 except KeyError:
755 raise ValueError("unknown archive format '%s'" % format)
756
757 func = format_info[0]
758 for arg, val in format_info[1]:
759 kwargs[arg] = val
760
761 if format != 'zip':
762 kwargs['owner'] = owner
763 kwargs['group'] = group
764
765 try:
766 filename = func(base_name, base_dir, **kwargs)
767 finally:
768 if root_dir is not None:
769 if logger is not None:
770 logger.debug("changing back to '%s'", save_cwd)
771 os.chdir(save_cwd)
772
773 return filename
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000774
775
776def get_unpack_formats():
777 """Returns a list of supported formats for unpacking.
778
779 Each element of the returned sequence is a tuple
780 (name, extensions, description)
781 """
782 formats = [(name, info[0], info[3]) for name, info in
783 _UNPACK_FORMATS.items()]
784 formats.sort()
785 return formats
786
787def _check_unpack_options(extensions, function, extra_args):
788 """Checks what gets registered as an unpacker."""
789 # first make sure no other unpacker is registered for this extension
790 existing_extensions = {}
791 for name, info in _UNPACK_FORMATS.items():
792 for ext in info[0]:
793 existing_extensions[ext] = name
794
795 for extension in extensions:
796 if extension in existing_extensions:
797 msg = '%s is already registered for "%s"'
798 raise RegistryError(msg % (extension,
799 existing_extensions[extension]))
800
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200801 if not callable(function):
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000802 raise TypeError('The registered function must be a callable')
803
804
805def register_unpack_format(name, extensions, function, extra_args=None,
806 description=''):
807 """Registers an unpack format.
808
809 `name` is the name of the format. `extensions` is a list of extensions
810 corresponding to the format.
811
812 `function` is the callable that will be
813 used to unpack archives. The callable will receive archives to unpack.
814 If it's unable to handle an archive, it needs to raise a ReadError
815 exception.
816
817 If provided, `extra_args` is a sequence of
818 (name, value) tuples that will be passed as arguments to the callable.
819 description can be provided to describe the format, and will be returned
820 by the get_unpack_formats() function.
821 """
822 if extra_args is None:
823 extra_args = []
824 _check_unpack_options(extensions, function, extra_args)
825 _UNPACK_FORMATS[name] = extensions, function, extra_args, description
826
827def unregister_unpack_format(name):
828 """Removes the pack format from the registery."""
829 del _UNPACK_FORMATS[name]
830
831def _ensure_directory(path):
832 """Ensure that the parent directory of `path` exists"""
833 dirname = os.path.dirname(path)
834 if not os.path.isdir(dirname):
835 os.makedirs(dirname)
836
837def _unpack_zipfile(filename, extract_dir):
838 """Unpack zip `filename` to `extract_dir`
839 """
840 try:
841 import zipfile
842 except ImportError:
843 raise ReadError('zlib not supported, cannot unpack this archive.')
844
845 if not zipfile.is_zipfile(filename):
846 raise ReadError("%s is not a zip file" % filename)
847
848 zip = zipfile.ZipFile(filename)
849 try:
850 for info in zip.infolist():
851 name = info.filename
852
853 # don't extract absolute paths or ones with .. in them
854 if name.startswith('/') or '..' in name:
855 continue
856
857 target = os.path.join(extract_dir, *name.split('/'))
858 if not target:
859 continue
860
861 _ensure_directory(target)
862 if not name.endswith('/'):
863 # file
864 data = zip.read(info.filename)
Éric Araujoc1b7e7f2011-09-18 23:12:30 +0200865 f = open(target, 'wb')
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000866 try:
867 f.write(data)
868 finally:
869 f.close()
870 del data
871 finally:
872 zip.close()
873
874def _unpack_tarfile(filename, extract_dir):
875 """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir`
876 """
877 try:
878 tarobj = tarfile.open(filename)
879 except tarfile.TarError:
880 raise ReadError(
881 "%s is not a compressed or uncompressed tar file" % filename)
882 try:
883 tarobj.extractall(extract_dir)
884 finally:
885 tarobj.close()
886
887_UNPACK_FORMATS = {
888 'gztar': (['.tar.gz', '.tgz'], _unpack_tarfile, [], "gzip'ed tar-file"),
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000889 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"),
890 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file")
891 }
892
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000893if _BZ2_SUPPORTED:
894 _UNPACK_FORMATS['bztar'] = (['.bz2'], _unpack_tarfile, [],
895 "bzip2'ed tar-file")
896
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000897def _find_unpack_format(filename):
898 for name, info in _UNPACK_FORMATS.items():
899 for extension in info[0]:
900 if filename.endswith(extension):
901 return name
902 return None
903
904def unpack_archive(filename, extract_dir=None, format=None):
905 """Unpack an archive.
906
907 `filename` is the name of the archive.
908
909 `extract_dir` is the name of the target directory, where the archive
910 is unpacked. If not provided, the current working directory is used.
911
912 `format` is the archive format: one of "zip", "tar", or "gztar". Or any
913 other registered format. If not provided, unpack_archive will use the
914 filename extension and see if an unpacker was registered for that
915 extension.
916
917 In case none is found, a ValueError is raised.
918 """
919 if extract_dir is None:
920 extract_dir = os.getcwd()
921
922 if format is not None:
923 try:
924 format_info = _UNPACK_FORMATS[format]
925 except KeyError:
926 raise ValueError("Unknown unpack format '{0}'".format(format))
927
Nick Coghlanabf202d2011-03-16 13:52:20 -0400928 func = format_info[1]
929 func(filename, extract_dir, **dict(format_info[2]))
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000930 else:
931 # we need to look at the registered unpackers supported extensions
932 format = _find_unpack_format(filename)
933 if format is None:
934 raise ReadError("Unknown archive format '{0}'".format(filename))
935
936 func = _UNPACK_FORMATS[format][1]
937 kwargs = dict(_UNPACK_FORMATS[format][2])
938 func(filename, extract_dir, **kwargs)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200939
Éric Araujoe4d5b8e2011-08-08 16:51:11 +0200940
941if hasattr(os, 'statvfs'):
942
943 __all__.append('disk_usage')
944 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200945
946 def disk_usage(path):
Éric Araujoe4d5b8e2011-08-08 16:51:11 +0200947 """Return disk usage statistics about the given path.
948
Sandro Tosif8ae4fa2012-04-23 20:07:15 +0200949 Returned value is a named tuple with attributes 'total', 'used' and
Éric Araujoe4d5b8e2011-08-08 16:51:11 +0200950 'free', which are the amount of total, used and free space, in bytes.
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200951 """
Éric Araujoe4d5b8e2011-08-08 16:51:11 +0200952 st = os.statvfs(path)
953 free = st.f_bavail * st.f_frsize
954 total = st.f_blocks * st.f_frsize
955 used = (st.f_blocks - st.f_bfree) * st.f_frsize
956 return _ntuple_diskusage(total, used, free)
957
958elif os.name == 'nt':
959
960 import nt
961 __all__.append('disk_usage')
962 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
963
964 def disk_usage(path):
965 """Return disk usage statistics about the given path.
966
967 Returned valus is a named tuple with attributes 'total', 'used' and
968 'free', which are the amount of total, used and free space, in bytes.
969 """
970 total, free = nt._getdiskusage(path)
971 used = total - free
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200972 return _ntuple_diskusage(total, used, free)
Sandro Tosid902a142011-08-22 23:28:27 +0200973
Éric Araujo0ac4a5d2011-09-01 08:31:51 +0200974
Sandro Tosid902a142011-08-22 23:28:27 +0200975def chown(path, user=None, group=None):
976 """Change owner user and group of the given path.
977
978 user and group can be the uid/gid or the user/group names, and in that case,
979 they are converted to their respective uid/gid.
980 """
981
982 if user is None and group is None:
983 raise ValueError("user and/or group must be set")
984
985 _user = user
986 _group = group
987
988 # -1 means don't change it
989 if user is None:
990 _user = -1
991 # user can either be an int (the uid) or a string (the system username)
992 elif isinstance(user, str):
993 _user = _get_uid(user)
994 if _user is None:
995 raise LookupError("no such user: {!r}".format(user))
996
997 if group is None:
998 _group = -1
999 elif not isinstance(group, int):
1000 _group = _get_gid(group)
1001 if _group is None:
1002 raise LookupError("no such group: {!r}".format(group))
1003
1004 os.chown(path, _user, _group)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001005
1006def get_terminal_size(fallback=(80, 24)):
1007 """Get the size of the terminal window.
1008
1009 For each of the two dimensions, the environment variable, COLUMNS
1010 and LINES respectively, is checked. If the variable is defined and
1011 the value is a positive integer, it is used.
1012
1013 When COLUMNS or LINES is not defined, which is the common case,
1014 the terminal connected to sys.__stdout__ is queried
1015 by invoking os.get_terminal_size.
1016
1017 If the terminal size cannot be successfully queried, either because
1018 the system doesn't support querying, or because we are not
1019 connected to a terminal, the value given in fallback parameter
1020 is used. Fallback defaults to (80, 24) which is the default
1021 size used by many terminal emulators.
1022
1023 The value returned is a named tuple of type os.terminal_size.
1024 """
1025 # columns, lines are the working values
1026 try:
1027 columns = int(os.environ['COLUMNS'])
1028 except (KeyError, ValueError):
1029 columns = 0
1030
1031 try:
1032 lines = int(os.environ['LINES'])
1033 except (KeyError, ValueError):
1034 lines = 0
1035
1036 # only query if necessary
1037 if columns <= 0 or lines <= 0:
1038 try:
1039 size = os.get_terminal_size(sys.__stdout__.fileno())
1040 except (NameError, OSError):
1041 size = os.terminal_size(fallback)
1042 if columns <= 0:
1043 columns = size.columns
1044 if lines <= 0:
1045 lines = size.lines
1046
1047 return os.terminal_size((columns, lines))
Brian Curtinc57a3452012-06-22 16:00:30 -05001048
1049def which(cmd, mode=os.F_OK | os.X_OK, path=None):
Brian Curtindc00f1e2012-06-22 22:49:12 -05001050 """Given a command, mode, and a PATH string, return the path which
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001051 conforms to the given mode on the PATH, or None if there is no such
1052 file.
1053
1054 `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
1055 of os.environ.get("PATH"), or can be overridden with a custom search
1056 path.
1057
1058 """
Brian Curtinc57a3452012-06-22 16:00:30 -05001059 # Check that a given file can be accessed with the correct mode.
1060 # Additionally check that `file` is not a directory, as on Windows
1061 # directories pass the os.access check.
1062 def _access_check(fn, mode):
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001063 return (os.path.exists(fn) and os.access(fn, mode)
1064 and not os.path.isdir(fn))
Brian Curtinc57a3452012-06-22 16:00:30 -05001065
1066 # Short circuit. If we're given a full path which matches the mode
1067 # and it exists, we're done here.
1068 if _access_check(cmd, mode):
1069 return cmd
1070
1071 path = (path or os.environ.get("PATH", os.defpath)).split(os.pathsep)
1072
1073 if sys.platform == "win32":
1074 # The current directory takes precedence on Windows.
1075 if not os.curdir in path:
1076 path.insert(0, os.curdir)
1077
1078 # PATHEXT is necessary to check on Windows.
1079 pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
1080 # See if the given file matches any of the expected path extensions.
1081 # This will allow us to short circuit when given "python.exe".
1082 matches = [cmd for ext in pathext if cmd.lower().endswith(ext.lower())]
Philip Jenvey88bc0d22012-06-23 15:54:38 -07001083 # If it does match, only test that one, otherwise we have to try
1084 # others.
1085 files = [cmd] if matches else [cmd + ext.lower() for ext in pathext]
Brian Curtinc57a3452012-06-22 16:00:30 -05001086 else:
1087 # On other platforms you don't have things like PATHEXT to tell you
1088 # what file suffixes are executable, so just pass on cmd as-is.
1089 files = [cmd]
1090
1091 seen = set()
1092 for dir in path:
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001093 dir = os.path.normcase(dir)
Brian Curtinc57a3452012-06-22 16:00:30 -05001094 if not dir in seen:
1095 seen.add(dir)
1096 for thefile in files:
1097 name = os.path.join(dir, thefile)
1098 if _access_check(name, mode):
1099 return name
1100 return None