blob: ce60c3b113799ac2794ae3a2d414dff86f998457 [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",
Éric Araujo0ac4a5d2011-09-01 08:31:51 +020039 "ignore_patterns", "chown"]
É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)
Guido van Rossumc6360141990-10-13 19:23:40 +0000112
Antoine Pitrou78091e62011-12-29 18:54:15 +0100113def copymode(src, dst, symlinks=False):
114 """Copy mode bits from src to dst.
Guido van Rossumc6360141990-10-13 19:23:40 +0000115
Antoine Pitrou78091e62011-12-29 18:54:15 +0100116 If the optional flag `symlinks` is set, symlinks aren't followed if and
117 only if both `src` and `dst` are symlinks. If `lchmod` isn't available (eg.
118 Linux), in these cases, this method does nothing.
119
120 """
121 if symlinks and os.path.islink(src) and os.path.islink(dst):
122 if hasattr(os, 'lchmod'):
123 stat_func, chmod_func = os.lstat, os.lchmod
124 else:
125 return
126 elif hasattr(os, 'chmod'):
127 stat_func, chmod_func = os.stat, os.chmod
128 else:
129 return
130
131 st = stat_func(src)
132 chmod_func(dst, stat.S_IMODE(st.st_mode))
133
134def copystat(src, dst, symlinks=False):
135 """Copy all stat info (mode bits, atime, mtime, flags) from src to dst.
136
137 If the optional flag `symlinks` is set, symlinks aren't followed if and
138 only if both `src` and `dst` are symlinks.
139
140 """
Larry Hastingsb1454482012-05-03 12:56:44 -0700141 def _nop(*args, ns=None):
Antoine Pitrou78091e62011-12-29 18:54:15 +0100142 pass
143
144 if symlinks and os.path.islink(src) and os.path.islink(dst):
145 stat_func = os.lstat
146 utime_func = os.lutimes if hasattr(os, 'lutimes') else _nop
147 chmod_func = os.lchmod if hasattr(os, 'lchmod') else _nop
148 chflags_func = os.lchflags if hasattr(os, 'lchflags') else _nop
149 else:
150 stat_func = os.stat
151 utime_func = os.utime if hasattr(os, 'utime') else _nop
152 chmod_func = os.chmod if hasattr(os, 'chmod') else _nop
153 chflags_func = os.chflags if hasattr(os, 'chflags') else _nop
154
155 st = stat_func(src)
Walter Dörwald294bbf32002-06-06 09:48:13 +0000156 mode = stat.S_IMODE(st.st_mode)
Larry Hastings76ad59b2012-05-03 00:30:07 -0700157 utime_func(dst, ns=(st.st_atime_ns, st.st_mtime_ns))
Antoine Pitrou78091e62011-12-29 18:54:15 +0100158 chmod_func(dst, mode)
159 if hasattr(st, 'st_flags'):
Antoine Pitrou910bd512010-03-22 20:11:09 +0000160 try:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100161 chflags_func(dst, st.st_flags)
Antoine Pitrou910bd512010-03-22 20:11:09 +0000162 except OSError as why:
Ned Deilybaf75712012-05-10 17:05:19 -0700163 for err in 'EOPNOTSUPP', 'ENOTSUP':
164 if hasattr(errno, err) and why.errno == getattr(errno, err):
165 break
166 else:
Antoine Pitrou910bd512010-03-22 20:11:09 +0000167 raise
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000168
Antoine Pitrou424246f2012-05-12 19:02:01 +0200169if hasattr(os, 'listxattr'):
170 def _copyxattr(src, dst, symlinks=False):
171 """Copy extended filesystem attributes from `src` to `dst`.
172
173 Overwrite existing attributes.
174
175 If the optional flag `symlinks` is set, symlinks won't be followed.
176
177 """
178 if symlinks:
179 listxattr = os.llistxattr
180 removexattr = os.lremovexattr
181 setxattr = os.lsetxattr
182 getxattr = os.lgetxattr
183 else:
184 listxattr = os.listxattr
185 removexattr = os.removexattr
186 setxattr = os.setxattr
187 getxattr = os.getxattr
188
189 for attr in listxattr(src):
190 try:
191 setxattr(dst, attr, getxattr(src, attr))
192 except OSError as e:
193 if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA):
194 raise
195else:
196 def _copyxattr(*args, **kwargs):
197 pass
198
Antoine Pitrou78091e62011-12-29 18:54:15 +0100199def copy(src, dst, symlinks=False):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000200 """Copy data and mode bits ("cp src dst").
Tim Peters495ad3c2001-01-15 01:36:40 +0000201
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000202 The destination may be a directory.
203
Antoine Pitrou78091e62011-12-29 18:54:15 +0100204 If the optional flag `symlinks` is set, symlinks won't be followed. This
205 resembles GNU's "cp -P src dst".
206
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000207 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000208 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000209 dst = os.path.join(dst, os.path.basename(src))
Antoine Pitrou78091e62011-12-29 18:54:15 +0100210 copyfile(src, dst, symlinks=symlinks)
211 copymode(src, dst, symlinks=symlinks)
Guido van Rossumc6360141990-10-13 19:23:40 +0000212
Antoine Pitrou78091e62011-12-29 18:54:15 +0100213def copy2(src, dst, symlinks=False):
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000214 """Copy data and all stat info ("cp -p src dst").
215
216 The destination may be a directory.
217
Antoine Pitrou78091e62011-12-29 18:54:15 +0100218 If the optional flag `symlinks` is set, symlinks won't be followed. This
219 resembles GNU's "cp -P src dst".
220
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000221 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000222 if os.path.isdir(dst):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000223 dst = os.path.join(dst, os.path.basename(src))
Antoine Pitrou78091e62011-12-29 18:54:15 +0100224 copyfile(src, dst, symlinks=symlinks)
225 copystat(src, dst, symlinks=symlinks)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200226 _copyxattr(src, dst, symlinks=symlinks)
Guido van Rossumc6360141990-10-13 19:23:40 +0000227
Georg Brandl2ee470f2008-07-16 12:55:28 +0000228def ignore_patterns(*patterns):
229 """Function that can be used as copytree() ignore parameter.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000230
Georg Brandl2ee470f2008-07-16 12:55:28 +0000231 Patterns is a sequence of glob-style patterns
232 that are used to exclude files"""
233 def _ignore_patterns(path, names):
234 ignored_names = []
235 for pattern in patterns:
236 ignored_names.extend(fnmatch.filter(names, pattern))
237 return set(ignored_names)
238 return _ignore_patterns
239
Tarek Ziadéfb437512010-04-20 08:57:33 +0000240def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
241 ignore_dangling_symlinks=False):
Tarek Ziadé5340db32010-04-19 22:30:51 +0000242 """Recursively copy a directory tree.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000243
244 The destination directory must not already exist.
Neal Norwitza4c93b62003-02-23 21:36:32 +0000245 If exception(s) occur, an Error is raised with a list of reasons.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000246
247 If the optional symlinks flag is true, symbolic links in the
248 source tree result in symbolic links in the destination tree; if
249 it is false, the contents of the files pointed to by symbolic
Tarek Ziadéfb437512010-04-20 08:57:33 +0000250 links are copied. If the file pointed by the symlink doesn't
251 exist, an exception will be added in the list of errors raised in
252 an Error exception at the end of the copy process.
253
254 You can set the optional ignore_dangling_symlinks flag to true if you
Tarek Ziadé8c26c7d2010-04-23 13:03:50 +0000255 want to silence this exception. Notice that this has no effect on
256 platforms that don't support os.symlink.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000257
Georg Brandl2ee470f2008-07-16 12:55:28 +0000258 The optional ignore argument is a callable. If given, it
259 is called with the `src` parameter, which is the directory
260 being visited by copytree(), and `names` which is the list of
261 `src` contents, as returned by os.listdir():
262
263 callable(src, names) -> ignored_names
264
265 Since copytree() is called recursively, the callable will be
266 called once for each directory that is copied. It returns a
267 list of names relative to the `src` directory that should
268 not be copied.
269
Tarek Ziadé5340db32010-04-19 22:30:51 +0000270 The optional copy_function argument is a callable that will be used
271 to copy each file. It will be called with the source path and the
272 destination path as arguments. By default, copy2() is used, but any
273 function that supports the same signature (like copy()) can be used.
Guido van Rossum9d0a3df1997-04-29 14:45:19 +0000274
275 """
Guido van Rossuma2baf461997-04-29 14:06:46 +0000276 names = os.listdir(src)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000277 if ignore is not None:
278 ignored_names = ignore(src, names)
279 else:
280 ignored_names = set()
281
Johannes Gijsberse4172ea2005-01-08 12:31:29 +0000282 os.makedirs(dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000283 errors = []
Guido van Rossuma2baf461997-04-29 14:06:46 +0000284 for name in names:
Georg Brandl2ee470f2008-07-16 12:55:28 +0000285 if name in ignored_names:
286 continue
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000287 srcname = os.path.join(src, name)
288 dstname = os.path.join(dst, name)
289 try:
Tarek Ziadéfb437512010-04-20 08:57:33 +0000290 if os.path.islink(srcname):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000291 linkto = os.readlink(srcname)
Tarek Ziadéfb437512010-04-20 08:57:33 +0000292 if symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100293 # We can't just leave it to `copy_function` because legacy
294 # code with a custom `copy_function` may rely on copytree
295 # doing the right thing.
Tarek Ziadéfb437512010-04-20 08:57:33 +0000296 os.symlink(linkto, dstname)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100297 copystat(srcname, dstname, symlinks=symlinks)
Tarek Ziadéfb437512010-04-20 08:57:33 +0000298 else:
299 # ignore dangling symlink if the flag is on
300 if not os.path.exists(linkto) and ignore_dangling_symlinks:
301 continue
302 # otherwise let the copy occurs. copy2 will raise an error
303 copy_function(srcname, dstname)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000304 elif os.path.isdir(srcname):
Tarek Ziadé5340db32010-04-19 22:30:51 +0000305 copytree(srcname, dstname, symlinks, ignore, copy_function)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000306 else:
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000307 # Will raise a SpecialFileError for unsupported file types
Tarek Ziadé5340db32010-04-19 22:30:51 +0000308 copy_function(srcname, dstname)
Georg Brandla1be88e2005-08-31 22:48:45 +0000309 # catch the Error from the recursive copytree so that we can
310 # continue with other files
Guido van Rossumb940e112007-01-10 16:19:56 +0000311 except Error as err:
Georg Brandla1be88e2005-08-31 22:48:45 +0000312 errors.extend(err.args[0])
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000313 except EnvironmentError as why:
314 errors.append((srcname, dstname, str(why)))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000315 try:
316 copystat(src, dst)
Guido van Rossumb940e112007-01-10 16:19:56 +0000317 except OSError as why:
Georg Brandl6aa2d1f2008-08-12 08:35:52 +0000318 if WindowsError is not None and isinstance(why, WindowsError):
319 # Copying file access times may fail on Windows
320 pass
321 else:
322 errors.extend((src, dst, str(why)))
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000323 if errors:
Collin Winterce36ad82007-08-30 01:19:48 +0000324 raise Error(errors)
Guido van Rossumd7673291998-02-06 21:38:09 +0000325
Barry Warsaw234d9a92003-01-24 17:36:15 +0000326def rmtree(path, ignore_errors=False, onerror=None):
Guido van Rossumd7673291998-02-06 21:38:09 +0000327 """Recursively delete a directory tree.
328
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000329 If ignore_errors is set, errors are ignored; otherwise, if onerror
330 is set, it is called to handle the error with arguments (func,
331 path, exc_info) where func is os.listdir, os.remove, or os.rmdir;
332 path is the argument to that function that caused it to fail; and
333 exc_info is a tuple returned by sys.exc_info(). If ignore_errors
334 is false and onerror is None, an exception is raised.
335
Guido van Rossumd7673291998-02-06 21:38:09 +0000336 """
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000337 if ignore_errors:
338 def onerror(*args):
Barry Warsaw234d9a92003-01-24 17:36:15 +0000339 pass
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000340 elif onerror is None:
341 def onerror(*args):
342 raise
Christian Heimes9bd667a2008-01-20 15:14:11 +0000343 try:
344 if os.path.islink(path):
345 # symlinks to directories are forbidden, see bug #1669
346 raise OSError("Cannot call rmtree on a symbolic link")
347 except OSError:
348 onerror(os.path.islink, path, sys.exc_info())
349 # can't continue even if onerror hook returns
350 return
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000351 names = []
352 try:
353 names = os.listdir(path)
Éric Araujocfcc9772011-08-10 20:54:33 +0200354 except os.error:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000355 onerror(os.listdir, path, sys.exc_info())
356 for name in names:
357 fullname = os.path.join(path, name)
358 try:
359 mode = os.lstat(fullname).st_mode
360 except os.error:
361 mode = 0
362 if stat.S_ISDIR(mode):
363 rmtree(fullname, ignore_errors, onerror)
Barry Warsaw234d9a92003-01-24 17:36:15 +0000364 else:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000365 try:
366 os.remove(fullname)
Éric Araujocfcc9772011-08-10 20:54:33 +0200367 except os.error:
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000368 onerror(os.remove, fullname, sys.exc_info())
369 try:
370 os.rmdir(path)
371 except os.error:
372 onerror(os.rmdir, path, sys.exc_info())
Guido van Rossumd7673291998-02-06 21:38:09 +0000373
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000374
Christian Heimesada8c3b2008-03-18 18:26:33 +0000375def _basename(path):
376 # A basename() variant which first strips the trailing slash, if present.
377 # Thus we always get the last component of the path, even for directories.
378 return os.path.basename(path.rstrip(os.path.sep))
379
380def move(src, dst):
381 """Recursively move a file or directory to another location. This is
382 similar to the Unix "mv" command.
383
384 If the destination is a directory or a symlink to a directory, the source
385 is moved inside the directory. The destination path must not already
386 exist.
387
388 If the destination already exists but is not a directory, it may be
389 overwritten depending on os.rename() semantics.
390
391 If the destination is on our current filesystem, then rename() is used.
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100392 Otherwise, src is copied to the destination and then removed. Symlinks are
393 recreated under the new name if os.rename() fails because of cross
394 filesystem renames.
395
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000396 A lot more could be done here... A look at a mv.c shows a lot of
397 the issues this implementation glosses over.
398
399 """
Christian Heimesada8c3b2008-03-18 18:26:33 +0000400 real_dst = dst
401 if os.path.isdir(dst):
Ronald Oussorenf51738b2011-05-06 10:23:04 +0200402 if _samefile(src, dst):
403 # We might be on a case insensitive filesystem,
404 # perform the rename anyway.
405 os.rename(src, dst)
406 return
407
Christian Heimesada8c3b2008-03-18 18:26:33 +0000408 real_dst = os.path.join(dst, _basename(src))
409 if os.path.exists(real_dst):
410 raise Error("Destination path '%s' already exists" % real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000411 try:
Christian Heimesada8c3b2008-03-18 18:26:33 +0000412 os.rename(src, real_dst)
Éric Araujocfcc9772011-08-10 20:54:33 +0200413 except OSError:
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +0100414 if os.path.islink(src):
415 linkto = os.readlink(src)
416 os.symlink(linkto, real_dst)
417 os.unlink(src)
418 elif os.path.isdir(src):
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000419 if _destinsrc(src, dst):
Collin Winterce36ad82007-08-30 01:19:48 +0000420 raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst))
Christian Heimesada8c3b2008-03-18 18:26:33 +0000421 copytree(src, real_dst, symlinks=True)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000422 rmtree(src)
423 else:
Christian Heimesada8c3b2008-03-18 18:26:33 +0000424 copy2(src, real_dst)
Martin v. Löwise9ce0b02002-10-07 13:23:24 +0000425 os.unlink(src)
Brett Cannon1c3fa182004-06-19 21:11:35 +0000426
Benjamin Peterson247a9b82009-02-20 04:09:19 +0000427def _destinsrc(src, dst):
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +0000428 src = abspath(src)
429 dst = abspath(dst)
430 if not src.endswith(os.path.sep):
431 src += os.path.sep
432 if not dst.endswith(os.path.sep):
433 dst += os.path.sep
434 return dst.startswith(src)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000435
436def _get_gid(name):
437 """Returns a gid, given a group name."""
438 if getgrnam is None or name is None:
439 return None
440 try:
441 result = getgrnam(name)
442 except KeyError:
443 result = None
444 if result is not None:
445 return result[2]
446 return None
447
448def _get_uid(name):
449 """Returns an uid, given a user name."""
450 if getpwnam is None or name is None:
451 return None
452 try:
453 result = getpwnam(name)
454 except KeyError:
455 result = None
456 if result is not None:
457 return result[2]
458 return None
459
460def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
461 owner=None, group=None, logger=None):
462 """Create a (possibly compressed) tar file from all the files under
463 'base_dir'.
464
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000465 'compress' must be "gzip" (the default), "bzip2", or None.
Tarek Ziadé396fad72010-02-23 05:30:31 +0000466
467 'owner' and 'group' can be used to define an owner and a group for the
468 archive that is being built. If not provided, the current owner and group
469 will be used.
470
Éric Araujo4433a5f2010-12-15 20:26:30 +0000471 The output tar file will be named 'base_name' + ".tar", possibly plus
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000472 the appropriate compression extension (".gz", or ".bz2").
Tarek Ziadé396fad72010-02-23 05:30:31 +0000473
474 Returns the output filename.
475 """
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000476 tar_compression = {'gzip': 'gz', None: ''}
477 compress_ext = {'gzip': '.gz'}
478
479 if _BZ2_SUPPORTED:
480 tar_compression['bzip2'] = 'bz2'
481 compress_ext['bzip2'] = '.bz2'
Tarek Ziadé396fad72010-02-23 05:30:31 +0000482
483 # flags for compression program, each element of list will be an argument
Éric Araujoc1b7e7f2011-09-18 23:12:30 +0200484 if compress is not None and compress not in compress_ext:
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000485 raise ValueError("bad value for 'compress', or compression format not "
486 "supported : {0}".format(compress))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000487
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000488 archive_name = base_name + '.tar' + compress_ext.get(compress, '')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000489 archive_dir = os.path.dirname(archive_name)
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000490
Tarek Ziadé396fad72010-02-23 05:30:31 +0000491 if not os.path.exists(archive_dir):
Éric Araujoac4e58e2011-01-29 20:32:11 +0000492 if logger is not None:
Éric Araujo43a7ee12011-08-19 02:55:11 +0200493 logger.info("creating %s", archive_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000494 if not dry_run:
495 os.makedirs(archive_dir)
496
Tarek Ziadé396fad72010-02-23 05:30:31 +0000497 # creating the tarball
Tarek Ziadé396fad72010-02-23 05:30:31 +0000498 if logger is not None:
499 logger.info('Creating tar archive')
500
501 uid = _get_uid(owner)
502 gid = _get_gid(group)
503
504 def _set_uid_gid(tarinfo):
505 if gid is not None:
506 tarinfo.gid = gid
507 tarinfo.gname = group
508 if uid is not None:
509 tarinfo.uid = uid
510 tarinfo.uname = owner
511 return tarinfo
512
513 if not dry_run:
514 tar = tarfile.open(archive_name, 'w|%s' % tar_compression[compress])
515 try:
516 tar.add(base_dir, filter=_set_uid_gid)
517 finally:
518 tar.close()
519
Tarek Ziadé396fad72010-02-23 05:30:31 +0000520 return archive_name
521
Tarek Ziadée2124162010-04-21 13:35:21 +0000522def _call_external_zip(base_dir, zip_filename, verbose=False, dry_run=False):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000523 # XXX see if we want to keep an external call here
524 if verbose:
525 zipoptions = "-r"
526 else:
527 zipoptions = "-rq"
528 from distutils.errors import DistutilsExecError
529 from distutils.spawn import spawn
530 try:
531 spawn(["zip", zipoptions, zip_filename, base_dir], dry_run=dry_run)
532 except DistutilsExecError:
533 # XXX really should distinguish between "couldn't find
534 # external 'zip' command" and "zip failed".
535 raise ExecError("unable to create zip file '%s': "
536 "could neither import the 'zipfile' module nor "
537 "find a standalone zip utility") % zip_filename
538
539def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None):
540 """Create a zip file from all the files under 'base_dir'.
541
Éric Araujo4433a5f2010-12-15 20:26:30 +0000542 The output zip file will be named 'base_name' + ".zip". Uses either the
Tarek Ziadé396fad72010-02-23 05:30:31 +0000543 "zipfile" Python module (if available) or the InfoZIP "zip" utility
544 (if installed and found on the default search path). If neither tool is
545 available, raises ExecError. Returns the name of the output zip
546 file.
547 """
548 zip_filename = base_name + ".zip"
549 archive_dir = os.path.dirname(base_name)
550
551 if not os.path.exists(archive_dir):
552 if logger is not None:
553 logger.info("creating %s", archive_dir)
554 if not dry_run:
555 os.makedirs(archive_dir)
556
557 # If zipfile module is not available, try spawning an external 'zip'
558 # command.
559 try:
560 import zipfile
561 except ImportError:
562 zipfile = None
563
564 if zipfile is None:
Tarek Ziadée2124162010-04-21 13:35:21 +0000565 _call_external_zip(base_dir, zip_filename, verbose, dry_run)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000566 else:
567 if logger is not None:
568 logger.info("creating '%s' and adding '%s' to it",
569 zip_filename, base_dir)
570
571 if not dry_run:
572 zip = zipfile.ZipFile(zip_filename, "w",
573 compression=zipfile.ZIP_DEFLATED)
574
575 for dirpath, dirnames, filenames in os.walk(base_dir):
576 for name in filenames:
577 path = os.path.normpath(os.path.join(dirpath, name))
578 if os.path.isfile(path):
579 zip.write(path, path)
580 if logger is not None:
581 logger.info("adding '%s'", path)
582 zip.close()
583
584 return zip_filename
585
586_ARCHIVE_FORMATS = {
587 'gztar': (_make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"),
Tarek Ziadé396fad72010-02-23 05:30:31 +0000588 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"),
Éric Araujoc1b7e7f2011-09-18 23:12:30 +0200589 'zip': (_make_zipfile, [], "ZIP file")
Tarek Ziadé396fad72010-02-23 05:30:31 +0000590 }
591
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000592if _BZ2_SUPPORTED:
593 _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')],
594 "bzip2'ed tar-file")
595
Tarek Ziadé396fad72010-02-23 05:30:31 +0000596def get_archive_formats():
597 """Returns a list of supported formats for archiving and unarchiving.
598
599 Each element of the returned sequence is a tuple (name, description)
600 """
601 formats = [(name, registry[2]) for name, registry in
602 _ARCHIVE_FORMATS.items()]
603 formats.sort()
604 return formats
605
606def register_archive_format(name, function, extra_args=None, description=''):
607 """Registers an archive format.
608
609 name is the name of the format. function is the callable that will be
610 used to create archives. If provided, extra_args is a sequence of
611 (name, value) tuples that will be passed as arguments to the callable.
612 description can be provided to describe the format, and will be returned
613 by the get_archive_formats() function.
614 """
615 if extra_args is None:
616 extra_args = []
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200617 if not callable(function):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000618 raise TypeError('The %s object is not callable' % function)
619 if not isinstance(extra_args, (tuple, list)):
620 raise TypeError('extra_args needs to be a sequence')
621 for element in extra_args:
Éric Araujoc1b7e7f2011-09-18 23:12:30 +0200622 if not isinstance(element, (tuple, list)) or len(element) !=2:
Tarek Ziadé396fad72010-02-23 05:30:31 +0000623 raise TypeError('extra_args elements are : (arg_name, value)')
624
625 _ARCHIVE_FORMATS[name] = (function, extra_args, description)
626
627def unregister_archive_format(name):
628 del _ARCHIVE_FORMATS[name]
629
630def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
631 dry_run=0, owner=None, group=None, logger=None):
632 """Create an archive file (eg. zip or tar).
633
634 'base_name' is the name of the file to create, minus any format-specific
Tarek Ziadé5e2be872010-04-20 21:40:47 +0000635 extension; 'format' is the archive format: one of "zip", "tar", "bztar"
636 or "gztar".
Tarek Ziadé396fad72010-02-23 05:30:31 +0000637
638 'root_dir' is a directory that will be the root directory of the
639 archive; ie. we typically chdir into 'root_dir' before creating the
640 archive. 'base_dir' is the directory where we start archiving from;
641 ie. 'base_dir' will be the common prefix of all files and
642 directories in the archive. 'root_dir' and 'base_dir' both default
643 to the current directory. Returns the name of the archive file.
644
645 'owner' and 'group' are used when creating a tar archive. By default,
646 uses the current owner and group.
647 """
648 save_cwd = os.getcwd()
649 if root_dir is not None:
650 if logger is not None:
651 logger.debug("changing into '%s'", root_dir)
652 base_name = os.path.abspath(base_name)
653 if not dry_run:
654 os.chdir(root_dir)
655
656 if base_dir is None:
657 base_dir = os.curdir
658
659 kwargs = {'dry_run': dry_run, 'logger': logger}
660
661 try:
662 format_info = _ARCHIVE_FORMATS[format]
663 except KeyError:
664 raise ValueError("unknown archive format '%s'" % format)
665
666 func = format_info[0]
667 for arg, val in format_info[1]:
668 kwargs[arg] = val
669
670 if format != 'zip':
671 kwargs['owner'] = owner
672 kwargs['group'] = group
673
674 try:
675 filename = func(base_name, base_dir, **kwargs)
676 finally:
677 if root_dir is not None:
678 if logger is not None:
679 logger.debug("changing back to '%s'", save_cwd)
680 os.chdir(save_cwd)
681
682 return filename
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000683
684
685def get_unpack_formats():
686 """Returns a list of supported formats for unpacking.
687
688 Each element of the returned sequence is a tuple
689 (name, extensions, description)
690 """
691 formats = [(name, info[0], info[3]) for name, info in
692 _UNPACK_FORMATS.items()]
693 formats.sort()
694 return formats
695
696def _check_unpack_options(extensions, function, extra_args):
697 """Checks what gets registered as an unpacker."""
698 # first make sure no other unpacker is registered for this extension
699 existing_extensions = {}
700 for name, info in _UNPACK_FORMATS.items():
701 for ext in info[0]:
702 existing_extensions[ext] = name
703
704 for extension in extensions:
705 if extension in existing_extensions:
706 msg = '%s is already registered for "%s"'
707 raise RegistryError(msg % (extension,
708 existing_extensions[extension]))
709
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200710 if not callable(function):
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000711 raise TypeError('The registered function must be a callable')
712
713
714def register_unpack_format(name, extensions, function, extra_args=None,
715 description=''):
716 """Registers an unpack format.
717
718 `name` is the name of the format. `extensions` is a list of extensions
719 corresponding to the format.
720
721 `function` is the callable that will be
722 used to unpack archives. The callable will receive archives to unpack.
723 If it's unable to handle an archive, it needs to raise a ReadError
724 exception.
725
726 If provided, `extra_args` is a sequence of
727 (name, value) tuples that will be passed as arguments to the callable.
728 description can be provided to describe the format, and will be returned
729 by the get_unpack_formats() function.
730 """
731 if extra_args is None:
732 extra_args = []
733 _check_unpack_options(extensions, function, extra_args)
734 _UNPACK_FORMATS[name] = extensions, function, extra_args, description
735
736def unregister_unpack_format(name):
737 """Removes the pack format from the registery."""
738 del _UNPACK_FORMATS[name]
739
740def _ensure_directory(path):
741 """Ensure that the parent directory of `path` exists"""
742 dirname = os.path.dirname(path)
743 if not os.path.isdir(dirname):
744 os.makedirs(dirname)
745
746def _unpack_zipfile(filename, extract_dir):
747 """Unpack zip `filename` to `extract_dir`
748 """
749 try:
750 import zipfile
751 except ImportError:
752 raise ReadError('zlib not supported, cannot unpack this archive.')
753
754 if not zipfile.is_zipfile(filename):
755 raise ReadError("%s is not a zip file" % filename)
756
757 zip = zipfile.ZipFile(filename)
758 try:
759 for info in zip.infolist():
760 name = info.filename
761
762 # don't extract absolute paths or ones with .. in them
763 if name.startswith('/') or '..' in name:
764 continue
765
766 target = os.path.join(extract_dir, *name.split('/'))
767 if not target:
768 continue
769
770 _ensure_directory(target)
771 if not name.endswith('/'):
772 # file
773 data = zip.read(info.filename)
Éric Araujoc1b7e7f2011-09-18 23:12:30 +0200774 f = open(target, 'wb')
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000775 try:
776 f.write(data)
777 finally:
778 f.close()
779 del data
780 finally:
781 zip.close()
782
783def _unpack_tarfile(filename, extract_dir):
784 """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir`
785 """
786 try:
787 tarobj = tarfile.open(filename)
788 except tarfile.TarError:
789 raise ReadError(
790 "%s is not a compressed or uncompressed tar file" % filename)
791 try:
792 tarobj.extractall(extract_dir)
793 finally:
794 tarobj.close()
795
796_UNPACK_FORMATS = {
797 'gztar': (['.tar.gz', '.tgz'], _unpack_tarfile, [], "gzip'ed tar-file"),
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000798 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"),
799 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file")
800 }
801
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000802if _BZ2_SUPPORTED:
803 _UNPACK_FORMATS['bztar'] = (['.bz2'], _unpack_tarfile, [],
804 "bzip2'ed tar-file")
805
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000806def _find_unpack_format(filename):
807 for name, info in _UNPACK_FORMATS.items():
808 for extension in info[0]:
809 if filename.endswith(extension):
810 return name
811 return None
812
813def unpack_archive(filename, extract_dir=None, format=None):
814 """Unpack an archive.
815
816 `filename` is the name of the archive.
817
818 `extract_dir` is the name of the target directory, where the archive
819 is unpacked. If not provided, the current working directory is used.
820
821 `format` is the archive format: one of "zip", "tar", or "gztar". Or any
822 other registered format. If not provided, unpack_archive will use the
823 filename extension and see if an unpacker was registered for that
824 extension.
825
826 In case none is found, a ValueError is raised.
827 """
828 if extract_dir is None:
829 extract_dir = os.getcwd()
830
831 if format is not None:
832 try:
833 format_info = _UNPACK_FORMATS[format]
834 except KeyError:
835 raise ValueError("Unknown unpack format '{0}'".format(format))
836
Nick Coghlanabf202d2011-03-16 13:52:20 -0400837 func = format_info[1]
838 func(filename, extract_dir, **dict(format_info[2]))
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000839 else:
840 # we need to look at the registered unpackers supported extensions
841 format = _find_unpack_format(filename)
842 if format is None:
843 raise ReadError("Unknown archive format '{0}'".format(filename))
844
845 func = _UNPACK_FORMATS[format][1]
846 kwargs = dict(_UNPACK_FORMATS[format][2])
847 func(filename, extract_dir, **kwargs)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200848
Éric Araujoe4d5b8e2011-08-08 16:51:11 +0200849
850if hasattr(os, 'statvfs'):
851
852 __all__.append('disk_usage')
853 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200854
855 def disk_usage(path):
Éric Araujoe4d5b8e2011-08-08 16:51:11 +0200856 """Return disk usage statistics about the given path.
857
Sandro Tosif8ae4fa2012-04-23 20:07:15 +0200858 Returned value is a named tuple with attributes 'total', 'used' and
Éric Araujoe4d5b8e2011-08-08 16:51:11 +0200859 'free', which are the amount of total, used and free space, in bytes.
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200860 """
Éric Araujoe4d5b8e2011-08-08 16:51:11 +0200861 st = os.statvfs(path)
862 free = st.f_bavail * st.f_frsize
863 total = st.f_blocks * st.f_frsize
864 used = (st.f_blocks - st.f_bfree) * st.f_frsize
865 return _ntuple_diskusage(total, used, free)
866
867elif os.name == 'nt':
868
869 import nt
870 __all__.append('disk_usage')
871 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
872
873 def disk_usage(path):
874 """Return disk usage statistics about the given path.
875
876 Returned valus is a named tuple with attributes 'total', 'used' and
877 'free', which are the amount of total, used and free space, in bytes.
878 """
879 total, free = nt._getdiskusage(path)
880 used = total - free
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200881 return _ntuple_diskusage(total, used, free)
Sandro Tosid902a142011-08-22 23:28:27 +0200882
Éric Araujo0ac4a5d2011-09-01 08:31:51 +0200883
Sandro Tosid902a142011-08-22 23:28:27 +0200884def chown(path, user=None, group=None):
885 """Change owner user and group of the given path.
886
887 user and group can be the uid/gid or the user/group names, and in that case,
888 they are converted to their respective uid/gid.
889 """
890
891 if user is None and group is None:
892 raise ValueError("user and/or group must be set")
893
894 _user = user
895 _group = group
896
897 # -1 means don't change it
898 if user is None:
899 _user = -1
900 # user can either be an int (the uid) or a string (the system username)
901 elif isinstance(user, str):
902 _user = _get_uid(user)
903 if _user is None:
904 raise LookupError("no such user: {!r}".format(user))
905
906 if group is None:
907 _group = -1
908 elif not isinstance(group, int):
909 _group = _get_gid(group)
910 if _group is None:
911 raise LookupError("no such group: {!r}".format(group))
912
913 os.chown(path, _user, _group)
Antoine Pitroubcf2b592012-02-08 23:28:36 +0100914
915def get_terminal_size(fallback=(80, 24)):
916 """Get the size of the terminal window.
917
918 For each of the two dimensions, the environment variable, COLUMNS
919 and LINES respectively, is checked. If the variable is defined and
920 the value is a positive integer, it is used.
921
922 When COLUMNS or LINES is not defined, which is the common case,
923 the terminal connected to sys.__stdout__ is queried
924 by invoking os.get_terminal_size.
925
926 If the terminal size cannot be successfully queried, either because
927 the system doesn't support querying, or because we are not
928 connected to a terminal, the value given in fallback parameter
929 is used. Fallback defaults to (80, 24) which is the default
930 size used by many terminal emulators.
931
932 The value returned is a named tuple of type os.terminal_size.
933 """
934 # columns, lines are the working values
935 try:
936 columns = int(os.environ['COLUMNS'])
937 except (KeyError, ValueError):
938 columns = 0
939
940 try:
941 lines = int(os.environ['LINES'])
942 except (KeyError, ValueError):
943 lines = 0
944
945 # only query if necessary
946 if columns <= 0 or lines <= 0:
947 try:
948 size = os.get_terminal_size(sys.__stdout__.fileno())
949 except (NameError, OSError):
950 size = os.terminal_size(fallback)
951 if columns <= 0:
952 columns = size.columns
953 if lines <= 0:
954 lines = size.lines
955
956 return os.terminal_size((columns, lines))