annotate Lib/shutil.py @ 79691:05c8928362ee

Merge __next__ method link fixes with 3.3.
author Ezio Melotti <ezio.melotti@gmail.com>
date Fri, 12 Oct 2012 13:46:37 +0300
parents e11642068f85
children c70d964b26fe
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
59060
df56ba1cb0af Merged revisions 78364 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 59056
diff changeset
1 """Utility functions for copying and archiving files and directory trees.
5349
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
2
11202
7eeeb0d2b0a4 Typo in comment (on Mac, it's the *resource* fork that's not copied,
Guido van Rossum <guido@python.org>
parents: 10289
diff changeset
3 XXX The functions here don't copy the resource fork or other metadata on Mac.
5349
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
4
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
5 """
5
5570dbb1ce55 Initial revision
Guido van Rossum <guido@python.org>
parents:
diff changeset
6
771
2e82dd0f8a9e posix -> os
Guido van Rossum <guido@python.org>
parents: 363
diff changeset
7 import os
10289
1e766de714de Add import sys, needed by reference to sys.exc_info() in rmtree().
Guido van Rossum <guido@python.org>
parents: 9872
diff changeset
8 import sys
5349
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
9 import stat
32386
686e5d38be42 shutil.move() will raise an exception when trying to move a directory into
Brett Cannon <bcannon@gmail.com>
parents: 28025
diff changeset
10 from os.path import abspath
48499
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
11 import fnmatch
59056
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
12 import collections
59919
1dc18412a7ee Merged revisions 79301 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 54594
diff changeset
13 import errno
61062
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
14 import tarfile
59056
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
15
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
16 try:
61087
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
17 import bz2
73345
fa82071bb7e1 Remove redundant imports.
Florent Xicluna <florent.xicluna@gmail.com>
parents: 73166
diff changeset
18 del bz2
61087
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
19 _BZ2_SUPPORTED = True
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
20 except ImportError:
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
21 _BZ2_SUPPORTED = False
5
5570dbb1ce55 Initial revision
Guido van Rossum <guido@python.org>
parents:
diff changeset
22
61087
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
23 try:
59056
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
24 from pwd import getpwnam
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
25 except ImportError:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
26 getpwnam = None
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
27
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
28 try:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
29 from grp import getgrnam
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
30 except ImportError:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
31 getgrnam = None
5
5570dbb1ce55 Initial revision
Guido van Rossum <guido@python.org>
parents:
diff changeset
32
59060
df56ba1cb0af Merged revisions 78364 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 59056
diff changeset
33 __all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2",
df56ba1cb0af Merged revisions 78364 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 59056
diff changeset
34 "copytree", "move", "rmtree", "Error", "SpecialFileError",
df56ba1cb0af Merged revisions 78364 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 59056
diff changeset
35 "ExecError", "make_archive", "get_archive_formats",
61062
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
36 "register_archive_format", "unregister_archive_format",
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
37 "get_unpack_formats", "register_unpack_format",
72017
8d1ccac9146d Merge 3.2
Éric Araujo <merwok@netwok.org>
parents: 71936 72016
diff changeset
38 "unregister_unpack_format", "unpack_archive",
77588
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
39 "ignore_patterns", "chown", "which"]
71781
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
40 # disk_usage is added later, if available on the platform
25641
13438586daa6 Patch #448038: Add move(). Report errors from copytree as in shutil.Error.
Martin v. Löwis <martin@v.loewis.de>
parents: 25170
diff changeset
41
35505
26ba3d4f4fc4 No need to import exceptions, they are builtins
Neal Norwitz <nnorwitz@gmail.com>
parents: 35501
diff changeset
42 class Error(EnvironmentError):
25641
13438586daa6 Patch #448038: Add move(). Report errors from copytree as in shutil.Error.
Martin v. Löwis <martin@v.loewis.de>
parents: 25170
diff changeset
43 pass
5
5570dbb1ce55 Initial revision
Guido van Rossum <guido@python.org>
parents:
diff changeset
44
79566
e11642068f85 Closes #1492704: Make shutil.copyfile() raise a distinct SameFileError
Hynek Schlawack <hs@ox.cx>
parents: 78762
diff changeset
45 class SameFileError(Error):
e11642068f85 Closes #1492704: Make shutil.copyfile() raise a distinct SameFileError
Hynek Schlawack <hs@ox.cx>
parents: 78762
diff changeset
46 """Raised when source and destination are the same file."""
e11642068f85 Closes #1492704: Make shutil.copyfile() raise a distinct SameFileError
Hynek Schlawack <hs@ox.cx>
parents: 78762
diff changeset
47
53653
960ef00d5214 Merged revisions 72178 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 51750
diff changeset
48 class SpecialFileError(EnvironmentError):
960ef00d5214 Merged revisions 72178 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 51750
diff changeset
49 """Raised when trying to do a kind of operation (e.g. copying) which is
960ef00d5214 Merged revisions 72178 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 51750
diff changeset
50 not supported on a special file (e.g. a named pipe)"""
960ef00d5214 Merged revisions 72178 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 51750
diff changeset
51
59056
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
52 class ExecError(EnvironmentError):
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
53 """Raised when a command could not be executed"""
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
54
61062
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
55 class ReadError(EnvironmentError):
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
56 """Raised when an archive cannot be read"""
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
57
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
58 class RegistryError(Exception):
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
59 """Raised when a registery operation with the archiving
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
60 and unpacking registeries fails"""
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
61
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
62
48680
7779af388aec Merged revisions 65459,65472,65481,65518,65536,65581,65609,65637,65641,65644-65645 via svnmerge from
Georg Brandl <georg@python.org>
parents: 48499
diff changeset
63 try:
7779af388aec Merged revisions 65459,65472,65481,65518,65536,65581,65609,65637,65641,65644-65645 via svnmerge from
Georg Brandl <georg@python.org>
parents: 48499
diff changeset
64 WindowsError
7779af388aec Merged revisions 65459,65472,65481,65518,65536,65581,65609,65637,65641,65644-65645 via svnmerge from
Georg Brandl <georg@python.org>
parents: 48499
diff changeset
65 except NameError:
7779af388aec Merged revisions 65459,65472,65481,65518,65536,65581,65609,65637,65641,65644-65645 via svnmerge from
Georg Brandl <georg@python.org>
parents: 48499
diff changeset
66 WindowsError = None
7779af388aec Merged revisions 65459,65472,65481,65518,65536,65581,65609,65637,65641,65644-65645 via svnmerge from
Georg Brandl <georg@python.org>
parents: 48499
diff changeset
67
13571
3a8c670309a2 apply patch #100868 from Moshe Zadka:
Greg Stein <gstein@lyra.org>
parents: 12285
diff changeset
68 def copyfileobj(fsrc, fdst, length=16*1024):
3a8c670309a2 apply patch #100868 from Moshe Zadka:
Greg Stein <gstein@lyra.org>
parents: 12285
diff changeset
69 """copy data from file-like object fsrc to file-like object fdst"""
3a8c670309a2 apply patch #100868 from Moshe Zadka:
Greg Stein <gstein@lyra.org>
parents: 12285
diff changeset
70 while 1:
3a8c670309a2 apply patch #100868 from Moshe Zadka:
Greg Stein <gstein@lyra.org>
parents: 12285
diff changeset
71 buf = fsrc.read(length)
3a8c670309a2 apply patch #100868 from Moshe Zadka:
Greg Stein <gstein@lyra.org>
parents: 12285
diff changeset
72 if not buf:
3a8c670309a2 apply patch #100868 from Moshe Zadka:
Greg Stein <gstein@lyra.org>
parents: 12285
diff changeset
73 break
3a8c670309a2 apply patch #100868 from Moshe Zadka:
Greg Stein <gstein@lyra.org>
parents: 12285
diff changeset
74 fdst.write(buf)
3a8c670309a2 apply patch #100868 from Moshe Zadka:
Greg Stein <gstein@lyra.org>
parents: 12285
diff changeset
75
33124
dc647df53921 Raise an exception when src and dst refer to the same file via a hard link or a
Johannes Gijsbers <jlg@dds.nl>
parents: 32652
diff changeset
76 def _samefile(src, dst):
dc647df53921 Raise an exception when src and dst refer to the same file via a hard link or a
Johannes Gijsbers <jlg@dds.nl>
parents: 32652
diff changeset
77 # Macintosh, Unix.
60726
71860cdb4886 Merged revisions 80218 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 59918
diff changeset
78 if hasattr(os.path, 'samefile'):
33128
c2384601a241 Catch OSError raised when src or dst argument to os.path.samefile doesn't
Johannes Gijsbers <jlg@dds.nl>
parents: 33124
diff changeset
79 try:
c2384601a241 Catch OSError raised when src or dst argument to os.path.samefile doesn't
Johannes Gijsbers <jlg@dds.nl>
parents: 33124
diff changeset
80 return os.path.samefile(src, dst)
c2384601a241 Catch OSError raised when src or dst argument to os.path.samefile doesn't
Johannes Gijsbers <jlg@dds.nl>
parents: 33124
diff changeset
81 except OSError:
c2384601a241 Catch OSError raised when src or dst argument to os.path.samefile doesn't
Johannes Gijsbers <jlg@dds.nl>
parents: 33124
diff changeset
82 return False
33124
dc647df53921 Raise an exception when src and dst refer to the same file via a hard link or a
Johannes Gijsbers <jlg@dds.nl>
parents: 32652
diff changeset
83
dc647df53921 Raise an exception when src and dst refer to the same file via a hard link or a
Johannes Gijsbers <jlg@dds.nl>
parents: 32652
diff changeset
84 # All other platforms: check for same pathname.
dc647df53921 Raise an exception when src and dst refer to the same file via a hard link or a
Johannes Gijsbers <jlg@dds.nl>
parents: 32652
diff changeset
85 return (os.path.normcase(os.path.abspath(src)) ==
dc647df53921 Raise an exception when src and dst refer to the same file via a hard link or a
Johannes Gijsbers <jlg@dds.nl>
parents: 32652
diff changeset
86 os.path.normcase(os.path.abspath(dst)))
15872
3685ef2a55a4 Whitespace normalization.
Tim Peters <tim.peters@gmail.com>
parents: 13571
diff changeset
87
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
88 def copyfile(src, dst, *, follow_symlinks=True):
74194
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
89 """Copy data from src to dst.
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
90
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
91 If follow_symlinks is not set and src is a symbolic link, a new
74194
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
92 symlink will be created instead of copying the file it points to.
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
93
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
94 """
33124
dc647df53921 Raise an exception when src and dst refer to the same file via a hard link or a
Johannes Gijsbers <jlg@dds.nl>
parents: 32652
diff changeset
95 if _samefile(src, dst):
79566
e11642068f85 Closes #1492704: Make shutil.copyfile() raise a distinct SameFileError
Hynek Schlawack <hs@ox.cx>
parents: 78762
diff changeset
96 raise SameFileError("{!r} and {!r} are the same file".format(src, dst))
33124
dc647df53921 Raise an exception when src and dst refer to the same file via a hard link or a
Johannes Gijsbers <jlg@dds.nl>
parents: 32652
diff changeset
97
53653
960ef00d5214 Merged revisions 72178 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 51750
diff changeset
98 for fn in [src, dst]:
960ef00d5214 Merged revisions 72178 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 51750
diff changeset
99 try:
960ef00d5214 Merged revisions 72178 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 51750
diff changeset
100 st = os.stat(fn)
960ef00d5214 Merged revisions 72178 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 51750
diff changeset
101 except OSError:
960ef00d5214 Merged revisions 72178 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 51750
diff changeset
102 # File most likely does not exist
960ef00d5214 Merged revisions 72178 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 51750
diff changeset
103 pass
54594
da33bed5d8c4 Merged revisions 73250 via svnmerge from
Benjamin Peterson <benjamin@python.org>
parents: 53653
diff changeset
104 else:
da33bed5d8c4 Merged revisions 73250 via svnmerge from
Benjamin Peterson <benjamin@python.org>
parents: 53653
diff changeset
105 # XXX What about other special files? (sockets, devices...)
da33bed5d8c4 Merged revisions 73250 via svnmerge from
Benjamin Peterson <benjamin@python.org>
parents: 53653
diff changeset
106 if stat.S_ISFIFO(st.st_mode):
da33bed5d8c4 Merged revisions 73250 via svnmerge from
Benjamin Peterson <benjamin@python.org>
parents: 53653
diff changeset
107 raise SpecialFileError("`%s` is a named pipe" % fn)
61289
78e7fc01c51a Merged revisions 80833 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 59919
diff changeset
108
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
109 if not follow_symlinks and os.path.islink(src):
74194
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
110 os.symlink(os.readlink(src), dst)
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
111 else:
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
112 with open(src, 'rb') as fsrc:
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
113 with open(dst, 'wb') as fdst:
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
114 copyfileobj(fsrc, fdst)
77514
8281233ec648 Fix #14772: Return the destination from some shutil functions.
Brian Curtin <brian@python.org>
parents: 76883
diff changeset
115 return dst
74194
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
116
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
117 def copymode(src, dst, *, follow_symlinks=True):
74194
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
118 """Copy mode bits from src to dst.
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
119
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
120 If follow_symlinks is not set, symlinks aren't followed if and only
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
121 if both `src` and `dst` are symlinks. If `lchmod` isn't available
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
122 (e.g. Linux) this method does nothing.
5
5570dbb1ce55 Initial revision
Guido van Rossum <guido@python.org>
parents:
diff changeset
123
74194
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
124 """
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
125 if not follow_symlinks and os.path.islink(src) and os.path.islink(dst):
74194
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
126 if hasattr(os, 'lchmod'):
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
127 stat_func, chmod_func = os.lstat, os.lchmod
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
128 else:
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
129 return
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
130 elif hasattr(os, 'chmod'):
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
131 stat_func, chmod_func = os.stat, os.chmod
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
132 else:
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
133 return
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
134
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
135 st = stat_func(src)
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
136 chmod_func(dst, stat.S_IMODE(st.st_mode))
5
5570dbb1ce55 Initial revision
Guido van Rossum <guido@python.org>
parents:
diff changeset
137
78101
5f62c317c202 - Issue #15238: shutil.copystat now copies Linux "extended attributes".
Larry Hastings <larry@hastings.org>
parents: 77846
diff changeset
138 if hasattr(os, 'listxattr'):
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
139 def _copyxattr(src, dst, *, follow_symlinks=True):
78101
5f62c317c202 - Issue #15238: shutil.copystat now copies Linux "extended attributes".
Larry Hastings <larry@hastings.org>
parents: 77846
diff changeset
140 """Copy extended filesystem attributes from `src` to `dst`.
5f62c317c202 - Issue #15238: shutil.copystat now copies Linux "extended attributes".
Larry Hastings <larry@hastings.org>
parents: 77846
diff changeset
141
5f62c317c202 - Issue #15238: shutil.copystat now copies Linux "extended attributes".
Larry Hastings <larry@hastings.org>
parents: 77846
diff changeset
142 Overwrite existing attributes.
5f62c317c202 - Issue #15238: shutil.copystat now copies Linux "extended attributes".
Larry Hastings <larry@hastings.org>
parents: 77846
diff changeset
143
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
144 If `follow_symlinks` is false, symlinks won't be followed.
78101
5f62c317c202 - Issue #15238: shutil.copystat now copies Linux "extended attributes".
Larry Hastings <larry@hastings.org>
parents: 77846
diff changeset
145
5f62c317c202 - Issue #15238: shutil.copystat now copies Linux "extended attributes".
Larry Hastings <larry@hastings.org>
parents: 77846
diff changeset
146 """
5
5570dbb1ce55 Initial revision
Guido van Rossum <guido@python.org>
parents:
diff changeset
147
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
148 for name in os.listxattr(src, follow_symlinks=follow_symlinks):
78101
5f62c317c202 - Issue #15238: shutil.copystat now copies Linux "extended attributes".
Larry Hastings <larry@hastings.org>
parents: 77846
diff changeset
149 try:
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
150 value = os.getxattr(src, name, follow_symlinks=follow_symlinks)
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
151 os.setxattr(dst, name, value, follow_symlinks=follow_symlinks)
78101
5f62c317c202 - Issue #15238: shutil.copystat now copies Linux "extended attributes".
Larry Hastings <larry@hastings.org>
parents: 77846
diff changeset
152 except OSError as e:
5f62c317c202 - Issue #15238: shutil.copystat now copies Linux "extended attributes".
Larry Hastings <larry@hastings.org>
parents: 77846
diff changeset
153 if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA):
5f62c317c202 - Issue #15238: shutil.copystat now copies Linux "extended attributes".
Larry Hastings <larry@hastings.org>
parents: 77846
diff changeset
154 raise
5f62c317c202 - Issue #15238: shutil.copystat now copies Linux "extended attributes".
Larry Hastings <larry@hastings.org>
parents: 77846
diff changeset
155 else:
5f62c317c202 - Issue #15238: shutil.copystat now copies Linux "extended attributes".
Larry Hastings <larry@hastings.org>
parents: 77846
diff changeset
156 def _copyxattr(*args, **kwargs):
5f62c317c202 - Issue #15238: shutil.copystat now copies Linux "extended attributes".
Larry Hastings <larry@hastings.org>
parents: 77846
diff changeset
157 pass
5f62c317c202 - Issue #15238: shutil.copystat now copies Linux "extended attributes".
Larry Hastings <larry@hastings.org>
parents: 77846
diff changeset
158
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
159 def copystat(src, dst, *, follow_symlinks=True):
74194
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
160 """Copy all stat info (mode bits, atime, mtime, flags) from src to dst.
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
161
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
162 If the optional flag `follow_symlinks` is not set, symlinks aren't followed if and
74194
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
163 only if both `src` and `dst` are symlinks.
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
164
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
165 """
77597
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
166 def _nop(*args, ns=None, follow_symlinks=None):
74194
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
167 pass
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
168
77597
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
169 # follow symlinks (aka don't not follow symlinks)
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
170 follow = follow_symlinks or not (os.path.islink(src) and os.path.islink(dst))
77597
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
171 if follow:
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
172 # use the real function if it exists
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
173 def lookup(name):
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
174 return getattr(os, name, _nop)
74194
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
175 else:
77597
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
176 # use the real function only if it exists
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
177 # *and* it supports follow_symlinks
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
178 def lookup(name):
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
179 fn = getattr(os, name, _nop)
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
180 if fn in os.supports_follow_symlinks:
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
181 return fn
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
182 return _nop
74194
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
183
77597
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
184 st = lookup("stat")(src, follow_symlinks=follow)
23697
c0e8c07ae1d6 Replace obsolete stat module constants with
Walter Dörwald <walter@livinglogic.de>
parents: 23627
diff changeset
185 mode = stat.S_IMODE(st.st_mode)
77597
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
186 lookup("utime")(dst, ns=(st.st_atime_ns, st.st_mtime_ns),
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
187 follow_symlinks=follow)
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
188 try:
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
189 lookup("chmod")(dst, mode, follow_symlinks=follow)
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
190 except NotImplementedError:
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
191 # if we got a NotImplementedError, it's because
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
192 # * follow_symlinks=False,
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
193 # * lchown() is unavailable, and
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
194 # * either
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
195 # * fchownat() is unvailable or
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
196 # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW.
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
197 # (it returned ENOSUP.)
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
198 # therefore we're out of options--we simply cannot chown the
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
199 # symlink. give up, suppress the error.
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
200 # (which is what shutil always did in this circumstance.)
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
201 pass
74194
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
202 if hasattr(st, 'st_flags'):
59919
1dc18412a7ee Merged revisions 79301 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 54594
diff changeset
203 try:
77597
27f9c26fdd8b Issue #14626: Large refactoring of functions / parameters in the os module.
Larry Hastings <larry@hastings.org>
parents: 77590
diff changeset
204 lookup("chflags")(dst, st.st_flags, follow_symlinks=follow)
59919
1dc18412a7ee Merged revisions 79301 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 54594
diff changeset
205 except OSError as why:
76870
ae141eebcf96 Issue #14662: Prevent shutil failures on OS X when destination does not
Ned Deily <nad@acm.org>
parents: 74791
diff changeset
206 for err in 'EOPNOTSUPP', 'ENOTSUP':
ae141eebcf96 Issue #14662: Prevent shutil failures on OS X when destination does not
Ned Deily <nad@acm.org>
parents: 74791
diff changeset
207 if hasattr(errno, err) and why.errno == getattr(errno, err):
ae141eebcf96 Issue #14662: Prevent shutil failures on OS X when destination does not
Ned Deily <nad@acm.org>
parents: 74791
diff changeset
208 break
ae141eebcf96 Issue #14662: Prevent shutil failures on OS X when destination does not
Ned Deily <nad@acm.org>
parents: 74791
diff changeset
209 else:
59919
1dc18412a7ee Merged revisions 79301 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 54594
diff changeset
210 raise
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
211 _copyxattr(src, dst, follow_symlinks=follow)
5
5570dbb1ce55 Initial revision
Guido van Rossum <guido@python.org>
parents:
diff changeset
212
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
213 def copy(src, dst, *, follow_symlinks=True):
77514
8281233ec648 Fix #14772: Return the destination from some shutil functions.
Brian Curtin <brian@python.org>
parents: 76883
diff changeset
214 """Copy data and mode bits ("cp src dst"). Return the file's destination.
15872
3685ef2a55a4 Whitespace normalization.
Tim Peters <tim.peters@gmail.com>
parents: 13571
diff changeset
215
5349
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
216 The destination may be a directory.
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
217
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
218 If follow_symlinks is false, symlinks won't be followed. This
74194
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
219 resembles GNU's "cp -P src dst".
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
220
79566
e11642068f85 Closes #1492704: Make shutil.copyfile() raise a distinct SameFileError
Hynek Schlawack <hs@ox.cx>
parents: 78762
diff changeset
221 If source and destination are the same file, a SameFileError will be
e11642068f85 Closes #1492704: Make shutil.copyfile() raise a distinct SameFileError
Hynek Schlawack <hs@ox.cx>
parents: 78762
diff changeset
222 raised.
e11642068f85 Closes #1492704: Make shutil.copyfile() raise a distinct SameFileError
Hynek Schlawack <hs@ox.cx>
parents: 78762
diff changeset
223
5349
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
224 """
5348
ae02ed2aac3f Reindented at 4 spaces.
Guido van Rossum <guido@python.org>
parents: 5347
diff changeset
225 if os.path.isdir(dst):
7755
fb4b4d069cc7 Mass check-in after untabifying all files that need it.
Guido van Rossum <guido@python.org>
parents: 7203
diff changeset
226 dst = os.path.join(dst, os.path.basename(src))
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
227 copyfile(src, dst, follow_symlinks=follow_symlinks)
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
228 copymode(src, dst, follow_symlinks=follow_symlinks)
77514
8281233ec648 Fix #14772: Return the destination from some shutil functions.
Brian Curtin <brian@python.org>
parents: 76883
diff changeset
229 return dst
5
5570dbb1ce55 Initial revision
Guido van Rossum <guido@python.org>
parents:
diff changeset
230
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
231 def copy2(src, dst, *, follow_symlinks=True):
77514
8281233ec648 Fix #14772: Return the destination from some shutil functions.
Brian Curtin <brian@python.org>
parents: 76883
diff changeset
232 """Copy data and all stat info ("cp -p src dst"). Return the file's
8281233ec648 Fix #14772: Return the destination from some shutil functions.
Brian Curtin <brian@python.org>
parents: 76883
diff changeset
233 destination."
5349
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
234
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
235 The destination may be a directory.
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
236
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
237 If follow_symlinks is false, symlinks won't be followed. This
74194
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
238 resembles GNU's "cp -P src dst".
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
239
5349
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
240 """
5348
ae02ed2aac3f Reindented at 4 spaces.
Guido van Rossum <guido@python.org>
parents: 5347
diff changeset
241 if os.path.isdir(dst):
7755
fb4b4d069cc7 Mass check-in after untabifying all files that need it.
Guido van Rossum <guido@python.org>
parents: 7203
diff changeset
242 dst = os.path.join(dst, os.path.basename(src))
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
243 copyfile(src, dst, follow_symlinks=follow_symlinks)
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
244 copystat(src, dst, follow_symlinks=follow_symlinks)
77514
8281233ec648 Fix #14772: Return the destination from some shutil functions.
Brian Curtin <brian@python.org>
parents: 76883
diff changeset
245 return dst
5
5570dbb1ce55 Initial revision
Guido van Rossum <guido@python.org>
parents:
diff changeset
246
48499
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
247 def ignore_patterns(*patterns):
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
248 """Function that can be used as copytree() ignore parameter.
5349
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
249
48499
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
250 Patterns is a sequence of glob-style patterns
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
251 that are used to exclude files"""
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
252 def _ignore_patterns(path, names):
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
253 ignored_names = []
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
254 for pattern in patterns:
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
255 ignored_names.extend(fnmatch.filter(names, pattern))
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
256 return set(ignored_names)
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
257 return _ignore_patterns
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
258
60751
82de0b488f2d Fixed #6547: Added the ignore_dangling_symlinks option to shutil.copytree
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60737
diff changeset
259 def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
82de0b488f2d Fixed #6547: Added the ignore_dangling_symlinks option to shutil.copytree
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60737
diff changeset
260 ignore_dangling_symlinks=False):
60737
be17bda5a658 Fixed #1540112: now shutil.copytree will let you provide your own copy() function
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60731
diff changeset
261 """Recursively copy a directory tree.
5349
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
262
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
263 The destination directory must not already exist.
28025
e63f1eccd250 Fix SF bug #691276, shutil.copytree documentation bug
Neal Norwitz <nnorwitz@gmail.com>
parents: 27361
diff changeset
264 If exception(s) occur, an Error is raised with a list of reasons.
5349
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
265
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
266 If the optional symlinks flag is true, symbolic links in the
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
267 source tree result in symbolic links in the destination tree; if
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
268 it is false, the contents of the files pointed to by symbolic
60751
82de0b488f2d Fixed #6547: Added the ignore_dangling_symlinks option to shutil.copytree
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60737
diff changeset
269 links are copied. If the file pointed by the symlink doesn't
82de0b488f2d Fixed #6547: Added the ignore_dangling_symlinks option to shutil.copytree
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60737
diff changeset
270 exist, an exception will be added in the list of errors raised in
82de0b488f2d Fixed #6547: Added the ignore_dangling_symlinks option to shutil.copytree
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60737
diff changeset
271 an Error exception at the end of the copy process.
82de0b488f2d Fixed #6547: Added the ignore_dangling_symlinks option to shutil.copytree
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60737
diff changeset
272
82de0b488f2d Fixed #6547: Added the ignore_dangling_symlinks option to shutil.copytree
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60737
diff changeset
273 You can set the optional ignore_dangling_symlinks flag to true if you
60892
d426bbfd5bd7 added a note about the ignore_dangling_symlinks option
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60810
diff changeset
274 want to silence this exception. Notice that this has no effect on
d426bbfd5bd7 added a note about the ignore_dangling_symlinks option
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60810
diff changeset
275 platforms that don't support os.symlink.
5349
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
276
48499
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
277 The optional ignore argument is a callable. If given, it
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
278 is called with the `src` parameter, which is the directory
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
279 being visited by copytree(), and `names` which is the list of
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
280 `src` contents, as returned by os.listdir():
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
281
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
282 callable(src, names) -> ignored_names
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
283
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
284 Since copytree() is called recursively, the callable will be
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
285 called once for each directory that is copied. It returns a
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
286 list of names relative to the `src` directory that should
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
287 not be copied.
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
288
60737
be17bda5a658 Fixed #1540112: now shutil.copytree will let you provide your own copy() function
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60731
diff changeset
289 The optional copy_function argument is a callable that will be used
be17bda5a658 Fixed #1540112: now shutil.copytree will let you provide your own copy() function
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60731
diff changeset
290 to copy each file. It will be called with the source path and the
be17bda5a658 Fixed #1540112: now shutil.copytree will let you provide your own copy() function
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60731
diff changeset
291 destination path as arguments. By default, copy2() is used, but any
be17bda5a658 Fixed #1540112: now shutil.copytree will let you provide your own copy() function
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60731
diff changeset
292 function that supports the same signature (like copy()) can be used.
5349
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
293
6ab392d7a52f Transformed comments to doc strings.
Guido van Rossum <guido@python.org>
parents: 5348
diff changeset
294 """
5348
ae02ed2aac3f Reindented at 4 spaces.
Guido van Rossum <guido@python.org>
parents: 5347
diff changeset
295 names = os.listdir(src)
48499
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
296 if ignore is not None:
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
297 ignored_names = ignore(src, names)
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
298 else:
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
299 ignored_names = set()
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
300
34364
19e61a2a5632 Patch #1094015:
Johannes Gijsbers <jlg@dds.nl>
parents: 33865
diff changeset
301 os.makedirs(dst)
25641
13438586daa6 Patch #448038: Add move(). Report errors from copytree as in shutil.Error.
Martin v. Löwis <martin@v.loewis.de>
parents: 25170
diff changeset
302 errors = []
5348
ae02ed2aac3f Reindented at 4 spaces.
Guido van Rossum <guido@python.org>
parents: 5347
diff changeset
303 for name in names:
48499
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
304 if name in ignored_names:
de0bf60f1245 Merged revisions 64722,64729,64753,64845-64846,64849,64871,64880-64882,64885,64888,64897,64900-64901,64915,64926-64929,64938-64941,64944,64961,64966,64973 via svnmerge from
Georg Brandl <georg@python.org>
parents: 45865
diff changeset
305 continue
7755
fb4b4d069cc7 Mass check-in after untabifying all files that need it.
Guido van Rossum <guido@python.org>
parents: 7203
diff changeset
306 srcname = os.path.join(src, name)
fb4b4d069cc7 Mass check-in after untabifying all files that need it.
Guido van Rossum <guido@python.org>
parents: 7203
diff changeset
307 dstname = os.path.join(dst, name)
fb4b4d069cc7 Mass check-in after untabifying all files that need it.
Guido van Rossum <guido@python.org>
parents: 7203
diff changeset
308 try:
60751
82de0b488f2d Fixed #6547: Added the ignore_dangling_symlinks option to shutil.copytree
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60737
diff changeset
309 if os.path.islink(srcname):
7755
fb4b4d069cc7 Mass check-in after untabifying all files that need it.
Guido van Rossum <guido@python.org>
parents: 7203
diff changeset
310 linkto = os.readlink(srcname)
60751
82de0b488f2d Fixed #6547: Added the ignore_dangling_symlinks option to shutil.copytree
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60737
diff changeset
311 if symlinks:
74194
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
312 # We can't just leave it to `copy_function` because legacy
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
313 # code with a custom `copy_function` may rely on copytree
cf57ef65bcd0 Issue #12715: Add an optional symlinks argument to shutil functions (copyfile, copymode, copystat, copy, copy2).
Antoine Pitrou <solipsis@pitrou.net>
parents: 73345
diff changeset
314 # doing the right thing.
60751
82de0b488f2d Fixed #6547: Added the ignore_dangling_symlinks option to shutil.copytree
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60737
diff changeset
315 os.symlink(linkto, dstname)
78121
758a9023d836 Issue #15202: Consistently use the name "follow_symlinks" for
Larry Hastings <larry@hastings.org>
parents: 78101
diff changeset
316 copystat(srcname, dstname, follow_symlinks=not symlinks)
60751
82de0b488f2d Fixed #6547: Added the ignore_dangling_symlinks option to shutil.copytree
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60737
diff changeset
317 else:
82de0b488f2d Fixed #6547: Added the ignore_dangling_symlinks option to shutil.copytree
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60737
diff changeset
318 # ignore dangling symlink if the flag is on
82de0b488f2d Fixed #6547: Added the ignore_dangling_symlinks option to shutil.copytree
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60737
diff changeset
319 if not os.path.exists(linkto) and ignore_dangling_symlinks:
82de0b488f2d Fixed #6547: Added the ignore_dangling_symlinks option to shutil.copytree
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60737
diff changeset
320 continue
82de0b488f2d Fixed #6547: Added the ignore_dangling_symlinks option to shutil.copytree
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60737
diff changeset
321 # otherwise let the copy occurs. copy2 will raise an error
82de0b488f2d Fixed #6547: Added the ignore_dangling_symlinks option to shutil.copytree
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60737
diff changeset
322 copy_function(srcname, dstname)
7755
fb4b4d069cc7 Mass check-in after untabifying all files that need it.
Guido van Rossum <guido@python.org>
parents: 7203
diff changeset
323 elif os.path.isdir(srcname):
60737
be17bda5a658 Fixed #1540112: now shutil.copytree will let you provide your own copy() function
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60731
diff changeset
324 copytree(srcname, dstname, symlinks, ignore, copy_function)
7755
fb4b4d069cc7 Mass check-in after untabifying all files that need it.
Guido van Rossum <guido@python.org>
parents: 7203
diff changeset
325 else:
53653
960ef00d5214 Merged revisions 72178 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 51750
diff changeset
326 # Will raise a SpecialFileError for unsupported file types
60737
be17bda5a658 Fixed #1540112: now shutil.copytree will let you provide your own copy() function
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60731
diff changeset
327 copy_function(srcname, dstname)
35501
ed65e0ad2215 patch [ 1242454 ] shutil.copytree() quits too soon after an error.
Georg Brandl <georg@python.org>
parents: 34485
diff changeset
328 # catch the Error from the recursive copytree so that we can
ed65e0ad2215 patch [ 1242454 ] shutil.copytree() quits too soon after an error.
Georg Brandl <georg@python.org>
parents: 34485
diff changeset
329 # continue with other files
40587
6b18a095c2e7 SF patch 1631942 by Collin Winter:
Guido van Rossum <guido@python.org>
parents: 39442
diff changeset
330 except Error as err:
35501
ed65e0ad2215 patch [ 1242454 ] shutil.copytree() quits too soon after an error.
Georg Brandl <georg@python.org>
parents: 34485
diff changeset
331 errors.extend(err.args[0])
53653
960ef00d5214 Merged revisions 72178 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 51750
diff changeset
332 except EnvironmentError as why:
960ef00d5214 Merged revisions 72178 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 51750
diff changeset
333 errors.append((srcname, dstname, str(why)))
39442
654c380cf8b9 Merged revisions 46753-51188 via svnmerge from
Thomas Wouters <thomas@python.org>
parents: 38453
diff changeset
334 try:
654c380cf8b9 Merged revisions 46753-51188 via svnmerge from
Thomas Wouters <thomas@python.org>
parents: 38453
diff changeset
335 copystat(src, dst)
40587
6b18a095c2e7 SF patch 1631942 by Collin Winter:
Guido van Rossum <guido@python.org>
parents: 39442
diff changeset
336 except OSError as why:
48680
7779af388aec Merged revisions 65459,65472,65481,65518,65536,65581,65609,65637,65641,65644-65645 via svnmerge from
Georg Brandl <georg@python.org>
parents: 48499
diff changeset
337 if WindowsError is not None and isinstance(why, WindowsError):
7779af388aec Merged revisions 65459,65472,65481,65518,65536,65581,65609,65637,65641,65644-65645 via svnmerge from
Georg Brandl <georg@python.org>
parents: 48499
diff changeset
338 # Copying file access times may fail on Windows
7779af388aec Merged revisions 65459,65472,65481,65518,65536,65581,65609,65637,65641,65644-65645 via svnmerge from
Georg Brandl <georg@python.org>
parents: 48499
diff changeset
339 pass
7779af388aec Merged revisions 65459,65472,65481,65518,65536,65581,65609,65637,65641,65644-65645 via svnmerge from
Georg Brandl <georg@python.org>
parents: 48499
diff changeset
340 else:
78761
a2bf95458eed Fix wrong way of adding Error information in shutil.copytree.
Georg Brandl <georg@python.org>
parents: 76870
diff changeset
341 errors.append((src, dst, str(why)))
25641
13438586daa6 Patch #448038: Add move(). Report errors from copytree as in shutil.Error.
Martin v. Löwis <martin@v.loewis.de>
parents: 25170
diff changeset
342 if errors:
43020
907a45df1295 Raise statement normalization in Lib/.
Collin Winter <collinw@gmail.com>
parents: 40893
diff changeset
343 raise Error(errors)
77514
8281233ec648 Fix #14772: Return the destination from some shutil functions.
Brian Curtin <brian@python.org>
parents: 76883
diff changeset
344 return dst
7203
8c129a567867 Added rmtree(), to recursively remove a directory tree.
Guido van Rossum <guido@python.org>
parents: 5349
diff changeset
345
77635
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
346 # version vulnerable to race conditions
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
347 def _rmtree_unsafe(path, onerror):
44828
ef7d72d98485 Merged revisions 60124-60142 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 43020
diff changeset
348 try:
ef7d72d98485 Merged revisions 60124-60142 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 43020
diff changeset
349 if os.path.islink(path):
ef7d72d98485 Merged revisions 60124-60142 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 43020
diff changeset
350 # symlinks to directories are forbidden, see bug #1669
ef7d72d98485 Merged revisions 60124-60142 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 43020
diff changeset
351 raise OSError("Cannot call rmtree on a symbolic link")
ef7d72d98485 Merged revisions 60124-60142 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 43020
diff changeset
352 except OSError:
ef7d72d98485 Merged revisions 60124-60142 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 43020
diff changeset
353 onerror(os.path.islink, path, sys.exc_info())
ef7d72d98485 Merged revisions 60124-60142 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 43020
diff changeset
354 # can't continue even if onerror hook returns
ef7d72d98485 Merged revisions 60124-60142 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 43020
diff changeset
355 return
33865
f196716ea0db Bug #1048941: shutil.rmtree error handling was always broken
Johannes Gijsbers <jlg@dds.nl>
parents: 33687
diff changeset
356 names = []
27361
891ec4d266d1 rmtree(): Make implementation agree with documentation (both latex and
Barry Warsaw <barry@python.org>
parents: 27096
diff changeset
357 try:
33865
f196716ea0db Bug #1048941: shutil.rmtree error handling was always broken
Johannes Gijsbers <jlg@dds.nl>
parents: 33687
diff changeset
358 names = os.listdir(path)
71828
552efc3eb45c Remove unused names in except clauses
Éric Araujo <merwok@netwok.org>
parents: 71781
diff changeset
359 except os.error:
33865
f196716ea0db Bug #1048941: shutil.rmtree error handling was always broken
Johannes Gijsbers <jlg@dds.nl>
parents: 33687
diff changeset
360 onerror(os.listdir, path, sys.exc_info())
f196716ea0db Bug #1048941: shutil.rmtree error handling was always broken
Johannes Gijsbers <jlg@dds.nl>
parents: 33687
diff changeset
361 for name in names:
f196716ea0db Bug #1048941: shutil.rmtree error handling was always broken
Johannes Gijsbers <jlg@dds.nl>
parents: 33687
diff changeset
362 fullname = os.path.join(path, name)
f196716ea0db Bug #1048941: shutil.rmtree error handling was always broken
Johannes Gijsbers <jlg@dds.nl>
parents: 33687
diff changeset
363 try:
f196716ea0db Bug #1048941: shutil.rmtree error handling was always broken
Johannes Gijsbers <jlg@dds.nl>
parents: 33687
diff changeset
364 mode = os.lstat(fullname).st_mode
f196716ea0db Bug #1048941: shutil.rmtree error handling was always broken
Johannes Gijsbers <jlg@dds.nl>
parents: 33687
diff changeset
365 except os.error:
f196716ea0db Bug #1048941: shutil.rmtree error handling was always broken
Johannes Gijsbers <jlg@dds.nl>
parents: 33687
diff changeset
366 mode = 0
f196716ea0db Bug #1048941: shutil.rmtree error handling was always broken
Johannes Gijsbers <jlg@dds.nl>
parents: 33687
diff changeset
367 if stat.S_ISDIR(mode):
77635
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
368 _rmtree_unsafe(fullname, onerror)
27361
891ec4d266d1 rmtree(): Make implementation agree with documentation (both latex and
Barry Warsaw <barry@python.org>
parents: 27096
diff changeset
369 else:
33865
f196716ea0db Bug #1048941: shutil.rmtree error handling was always broken
Johannes Gijsbers <jlg@dds.nl>
parents: 33687
diff changeset
370 try:
77642
53fc7f59c7bb #4489: Fix usage of fd-based functions to new api introduced earlier today
Hynek Schlawack <hs@ox.cx>
parents: 77635
diff changeset
371 os.unlink(fullname)
71828
552efc3eb45c Remove unused names in except clauses
Éric Araujo <merwok@netwok.org>
parents: 71781
diff changeset
372 except os.error:
77642
53fc7f59c7bb #4489: Fix usage of fd-based functions to new api introduced earlier today
Hynek Schlawack <hs@ox.cx>
parents: 77635
diff changeset
373 onerror(os.unlink, fullname, sys.exc_info())
33865
f196716ea0db Bug #1048941: shutil.rmtree error handling was always broken
Johannes Gijsbers <jlg@dds.nl>
parents: 33687
diff changeset
374 try:
f196716ea0db Bug #1048941: shutil.rmtree error handling was always broken
Johannes Gijsbers <jlg@dds.nl>
parents: 33687
diff changeset
375 os.rmdir(path)
f196716ea0db Bug #1048941: shutil.rmtree error handling was always broken
Johannes Gijsbers <jlg@dds.nl>
parents: 33687
diff changeset
376 except os.error:
f196716ea0db Bug #1048941: shutil.rmtree error handling was always broken
Johannes Gijsbers <jlg@dds.nl>
parents: 33687
diff changeset
377 onerror(os.rmdir, path, sys.exc_info())
7203
8c129a567867 Added rmtree(), to recursively remove a directory tree.
Guido van Rossum <guido@python.org>
parents: 5349
diff changeset
378
77635
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
379 # Version using fd-based APIs to protect against races
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
380 def _rmtree_safe_fd(topfd, path, onerror):
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
381 names = []
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
382 try:
77642
53fc7f59c7bb #4489: Fix usage of fd-based functions to new api introduced earlier today
Hynek Schlawack <hs@ox.cx>
parents: 77635
diff changeset
383 names = os.listdir(topfd)
77635
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
384 except os.error:
77642
53fc7f59c7bb #4489: Fix usage of fd-based functions to new api introduced earlier today
Hynek Schlawack <hs@ox.cx>
parents: 77635
diff changeset
385 onerror(os.listdir, path, sys.exc_info())
77635
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
386 for name in names:
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
387 fullname = os.path.join(path, name)
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
388 try:
77829
f9f798f1421e #4489: Don't follow ever symlinks in rmtree
Hynek Schlawack <hs@ox.cx>
parents: 77767
diff changeset
389 orig_st = os.stat(name, dir_fd=topfd, follow_symlinks=False)
77635
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
390 mode = orig_st.st_mode
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
391 except os.error:
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
392 mode = 0
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
393 if stat.S_ISDIR(mode):
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
394 try:
77642
53fc7f59c7bb #4489: Fix usage of fd-based functions to new api introduced earlier today
Hynek Schlawack <hs@ox.cx>
parents: 77635
diff changeset
395 dirfd = os.open(name, os.O_RDONLY, dir_fd=topfd)
77635
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
396 except os.error:
77642
53fc7f59c7bb #4489: Fix usage of fd-based functions to new api introduced earlier today
Hynek Schlawack <hs@ox.cx>
parents: 77635
diff changeset
397 onerror(os.open, fullname, sys.exc_info())
77635
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
398 else:
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
399 try:
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
400 if os.path.samestat(orig_st, os.fstat(dirfd)):
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
401 _rmtree_safe_fd(dirfd, fullname, onerror)
77835
9134bb4d0578 #4489: Use dir_fd in rmdir in _rmtree_safe_fd()
Hynek Schlawack <hs@ox.cx>
parents: 77829
diff changeset
402 try:
9134bb4d0578 #4489: Use dir_fd in rmdir in _rmtree_safe_fd()
Hynek Schlawack <hs@ox.cx>
parents: 77829
diff changeset
403 os.rmdir(name, dir_fd=topfd)
9134bb4d0578 #4489: Use dir_fd in rmdir in _rmtree_safe_fd()
Hynek Schlawack <hs@ox.cx>
parents: 77829
diff changeset
404 except os.error:
9134bb4d0578 #4489: Use dir_fd in rmdir in _rmtree_safe_fd()
Hynek Schlawack <hs@ox.cx>
parents: 77829
diff changeset
405 onerror(os.rmdir, fullname, sys.exc_info())
77635
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
406 finally:
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
407 os.close(dirfd)
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
408 else:
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
409 try:
77642
53fc7f59c7bb #4489: Fix usage of fd-based functions to new api introduced earlier today
Hynek Schlawack <hs@ox.cx>
parents: 77635
diff changeset
410 os.unlink(name, dir_fd=topfd)
77635
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
411 except os.error:
77642
53fc7f59c7bb #4489: Fix usage of fd-based functions to new api introduced earlier today
Hynek Schlawack <hs@ox.cx>
parents: 77635
diff changeset
412 onerror(os.unlink, fullname, sys.exc_info())
77635
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
413
77846
992be49127e1 Check for all used fd-based functions in shutil.rmdir, closes #15218
Hynek Schlawack <hs@ox.cx>
parents: 77835
diff changeset
414 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
992be49127e1 Check for all used fd-based functions in shutil.rmdir, closes #15218
Hynek Schlawack <hs@ox.cx>
parents: 77835
diff changeset
415 os.supports_dir_fd and
992be49127e1 Check for all used fd-based functions in shutil.rmdir, closes #15218
Hynek Schlawack <hs@ox.cx>
parents: 77835
diff changeset
416 os.listdir in os.supports_fd and
992be49127e1 Check for all used fd-based functions in shutil.rmdir, closes #15218
Hynek Schlawack <hs@ox.cx>
parents: 77835
diff changeset
417 os.stat in os.supports_follow_symlinks)
77668
c2be81151994 Issue #4489: Rename the feature marker for the symlink resistant rmtree and store it as a function attribute
Nick Coghlan <ncoghlan@gmail.com>
parents: 77660
diff changeset
418
77635
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
419 def rmtree(path, ignore_errors=False, onerror=None):
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
420 """Recursively delete a directory tree.
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
421
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
422 If ignore_errors is set, errors are ignored; otherwise, if onerror
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
423 is set, it is called to handle the error with arguments (func,
77642
53fc7f59c7bb #4489: Fix usage of fd-based functions to new api introduced earlier today
Hynek Schlawack <hs@ox.cx>
parents: 77635
diff changeset
424 path, exc_info) where func is platform and implementation dependent;
77635
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
425 path is the argument to that function that caused it to fail; and
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
426 exc_info is a tuple returned by sys.exc_info(). If ignore_errors
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
427 is false and onerror is None, an exception is raised.
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
428
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
429 """
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
430 if ignore_errors:
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
431 def onerror(*args):
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
432 pass
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
433 elif onerror is None:
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
434 def onerror(*args):
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
435 raise
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
436 if _use_fd_functions:
77767
2e2329aeb5c1 #4489 Make fd based rmtree work on bytes
Hynek Schlawack <hs@ox.cx>
parents: 77668
diff changeset
437 # While the unsafe rmtree works fine on bytes, the fd based does not.
2e2329aeb5c1 #4489 Make fd based rmtree work on bytes
Hynek Schlawack <hs@ox.cx>
parents: 77668
diff changeset
438 if isinstance(path, bytes):
2e2329aeb5c1 #4489 Make fd based rmtree work on bytes
Hynek Schlawack <hs@ox.cx>
parents: 77668
diff changeset
439 path = os.fsdecode(path)
77635
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
440 # Note: To guard against symlink races, we use the standard
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
441 # lstat()/open()/fstat() trick.
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
442 try:
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
443 orig_st = os.lstat(path)
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
444 except Exception:
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
445 onerror(os.lstat, path, sys.exc_info())
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
446 return
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
447 try:
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
448 fd = os.open(path, os.O_RDONLY)
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
449 except Exception:
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
450 onerror(os.lstat, path, sys.exc_info())
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
451 return
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
452 try:
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
453 if (stat.S_ISDIR(orig_st.st_mode) and
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
454 os.path.samestat(orig_st, os.fstat(fd))):
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
455 _rmtree_safe_fd(fd, path, onerror)
77835
9134bb4d0578 #4489: Use dir_fd in rmdir in _rmtree_safe_fd()
Hynek Schlawack <hs@ox.cx>
parents: 77829
diff changeset
456 try:
9134bb4d0578 #4489: Use dir_fd in rmdir in _rmtree_safe_fd()
Hynek Schlawack <hs@ox.cx>
parents: 77829
diff changeset
457 os.rmdir(path)
9134bb4d0578 #4489: Use dir_fd in rmdir in _rmtree_safe_fd()
Hynek Schlawack <hs@ox.cx>
parents: 77829
diff changeset
458 except os.error:
9134bb4d0578 #4489: Use dir_fd in rmdir in _rmtree_safe_fd()
Hynek Schlawack <hs@ox.cx>
parents: 77829
diff changeset
459 onerror(os.rmdir, path, sys.exc_info())
77829
f9f798f1421e #4489: Don't follow ever symlinks in rmtree
Hynek Schlawack <hs@ox.cx>
parents: 77767
diff changeset
460 else:
77635
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
461 raise NotADirectoryError(20,
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
462 "Not a directory: '{}'".format(path))
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
463 finally:
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
464 os.close(fd)
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
465 else:
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
466 return _rmtree_unsafe(path, onerror)
c910af2e3c98 #4489: Add a shutil.rmtree that isn't suspectible to symlink attacks
Hynek Schlawack <hs@ox.cx>
parents: 77610
diff changeset
467
77668
c2be81151994 Issue #4489: Rename the feature marker for the symlink resistant rmtree and store it as a function attribute
Nick Coghlan <ncoghlan@gmail.com>
parents: 77660
diff changeset
468 # Allow introspection of whether or not the hardening against symlink
c2be81151994 Issue #4489: Rename the feature marker for the symlink resistant rmtree and store it as a function attribute
Nick Coghlan <ncoghlan@gmail.com>
parents: 77660
diff changeset
469 # attacks is supported on the current platform
c2be81151994 Issue #4489: Rename the feature marker for the symlink resistant rmtree and store it as a function attribute
Nick Coghlan <ncoghlan@gmail.com>
parents: 77660
diff changeset
470 rmtree.avoids_symlink_attacks = _use_fd_functions
45865
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
471
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
472 def _basename(path):
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
473 # A basename() variant which first strips the trailing slash, if present.
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
474 # Thus we always get the last component of the path, even for directories.
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
475 return os.path.basename(path.rstrip(os.path.sep))
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
476
25641
13438586daa6 Patch #448038: Add move(). Report errors from copytree as in shutil.Error.
Martin v. Löwis <martin@v.loewis.de>
parents: 25170
diff changeset
477 def move(src, dst):
45865
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
478 """Recursively move a file or directory to another location. This is
77514
8281233ec648 Fix #14772: Return the destination from some shutil functions.
Brian Curtin <brian@python.org>
parents: 76883
diff changeset
479 similar to the Unix "mv" command. Return the file or directory's
8281233ec648 Fix #14772: Return the destination from some shutil functions.
Brian Curtin <brian@python.org>
parents: 76883
diff changeset
480 destination.
25641
13438586daa6 Patch #448038: Add move(). Report errors from copytree as in shutil.Error.
Martin v. Löwis <martin@v.loewis.de>
parents: 25170
diff changeset
481
45865
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
482 If the destination is a directory or a symlink to a directory, the source
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
483 is moved inside the directory. The destination path must not already
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
484 exist.
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
485
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
486 If the destination already exists but is not a directory, it may be
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
487 overwritten depending on os.rename() semantics.
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
488
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
489 If the destination is on our current filesystem, then rename() is used.
74288
1ea8b7233fd7 Issue #9993: When the source and destination are on different filesystems,
Antoine Pitrou <solipsis@pitrou.net>
parents: 74194
diff changeset
490 Otherwise, src is copied to the destination and then removed. Symlinks are
1ea8b7233fd7 Issue #9993: When the source and destination are on different filesystems,
Antoine Pitrou <solipsis@pitrou.net>
parents: 74194
diff changeset
491 recreated under the new name if os.rename() fails because of cross
1ea8b7233fd7 Issue #9993: When the source and destination are on different filesystems,
Antoine Pitrou <solipsis@pitrou.net>
parents: 74194
diff changeset
492 filesystem renames.
1ea8b7233fd7 Issue #9993: When the source and destination are on different filesystems,
Antoine Pitrou <solipsis@pitrou.net>
parents: 74194
diff changeset
493
25641
13438586daa6 Patch #448038: Add move(). Report errors from copytree as in shutil.Error.
Martin v. Löwis <martin@v.loewis.de>
parents: 25170
diff changeset
494 A lot more could be done here... A look at a mv.c shows a lot of
13438586daa6 Patch #448038: Add move(). Report errors from copytree as in shutil.Error.
Martin v. Löwis <martin@v.loewis.de>
parents: 25170
diff changeset
495 the issues this implementation glosses over.
13438586daa6 Patch #448038: Add move(). Report errors from copytree as in shutil.Error.
Martin v. Löwis <martin@v.loewis.de>
parents: 25170
diff changeset
496
13438586daa6 Patch #448038: Add move(). Report errors from copytree as in shutil.Error.
Martin v. Löwis <martin@v.loewis.de>
parents: 25170
diff changeset
497 """
45865
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
498 real_dst = dst
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
499 if os.path.isdir(dst):
69869
26da299ca88e Fix for issue 10684: Folders get deleted when trying to change case with shutil.move (case insensitive file systems only)
Ronald Oussoren <ronaldoussoren@mac.com>
parents: 61295
diff changeset
500 if _samefile(src, dst):
26da299ca88e Fix for issue 10684: Folders get deleted when trying to change case with shutil.move (case insensitive file systems only)
Ronald Oussoren <ronaldoussoren@mac.com>
parents: 61295
diff changeset
501 # We might be on a case insensitive filesystem,
26da299ca88e Fix for issue 10684: Folders get deleted when trying to change case with shutil.move (case insensitive file systems only)
Ronald Oussoren <ronaldoussoren@mac.com>
parents: 61295
diff changeset
502 # perform the rename anyway.
26da299ca88e Fix for issue 10684: Folders get deleted when trying to change case with shutil.move (case insensitive file systems only)
Ronald Oussoren <ronaldoussoren@mac.com>
parents: 61295
diff changeset
503 os.rename(src, dst)
26da299ca88e Fix for issue 10684: Folders get deleted when trying to change case with shutil.move (case insensitive file systems only)
Ronald Oussoren <ronaldoussoren@mac.com>
parents: 61295
diff changeset
504 return
26da299ca88e Fix for issue 10684: Folders get deleted when trying to change case with shutil.move (case insensitive file systems only)
Ronald Oussoren <ronaldoussoren@mac.com>
parents: 61295
diff changeset
505
45865
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
506 real_dst = os.path.join(dst, _basename(src))
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
507 if os.path.exists(real_dst):
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
508 raise Error("Destination path '%s' already exists" % real_dst)
25641
13438586daa6 Patch #448038: Add move(). Report errors from copytree as in shutil.Error.
Martin v. Löwis <martin@v.loewis.de>
parents: 25170
diff changeset
509 try:
45865
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
510 os.rename(src, real_dst)
71828
552efc3eb45c Remove unused names in except clauses
Éric Araujo <merwok@netwok.org>
parents: 71781
diff changeset
511 except OSError:
74288
1ea8b7233fd7 Issue #9993: When the source and destination are on different filesystems,
Antoine Pitrou <solipsis@pitrou.net>
parents: 74194
diff changeset
512 if os.path.islink(src):
1ea8b7233fd7 Issue #9993: When the source and destination are on different filesystems,
Antoine Pitrou <solipsis@pitrou.net>
parents: 74194
diff changeset
513 linkto = os.readlink(src)
1ea8b7233fd7 Issue #9993: When the source and destination are on different filesystems,
Antoine Pitrou <solipsis@pitrou.net>
parents: 74194
diff changeset
514 os.symlink(linkto, real_dst)
1ea8b7233fd7 Issue #9993: When the source and destination are on different filesystems,
Antoine Pitrou <solipsis@pitrou.net>
parents: 74194
diff changeset
515 os.unlink(src)
1ea8b7233fd7 Issue #9993: When the source and destination are on different filesystems,
Antoine Pitrou <solipsis@pitrou.net>
parents: 74194
diff changeset
516 elif os.path.isdir(src):
51750
db8db31fdb4c Merged revisions 69415,69591,69593 via svnmerge from
Benjamin Peterson <benjamin@python.org>
parents: 51180
diff changeset
517 if _destinsrc(src, dst):
43020
907a45df1295 Raise statement normalization in Lib/.
Collin Winter <collinw@gmail.com>
parents: 40893
diff changeset
518 raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst))
45865
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
519 copytree(src, real_dst, symlinks=True)
25641
13438586daa6 Patch #448038: Add move(). Report errors from copytree as in shutil.Error.
Martin v. Löwis <martin@v.loewis.de>
parents: 25170
diff changeset
520 rmtree(src)
13438586daa6 Patch #448038: Add move(). Report errors from copytree as in shutil.Error.
Martin v. Löwis <martin@v.loewis.de>
parents: 25170
diff changeset
521 else:
45865
e0e8bef0d5ec Merged revisions 61520,61523-61528,61532 via svnmerge from
Christian Heimes <christian@cheimes.de>
parents: 44828
diff changeset
522 copy2(src, real_dst)
25641
13438586daa6 Patch #448038: Add move(). Report errors from copytree as in shutil.Error.
Martin v. Löwis <martin@v.loewis.de>
parents: 25170
diff changeset
523 os.unlink(src)
77514
8281233ec648 Fix #14772: Return the destination from some shutil functions.
Brian Curtin <brian@python.org>
parents: 76883
diff changeset
524 return real_dst
32386
686e5d38be42 shutil.move() will raise an exception when trying to move a directory into
Brett Cannon <bcannon@gmail.com>
parents: 28025
diff changeset
525
51750
db8db31fdb4c Merged revisions 69415,69591,69593 via svnmerge from
Benjamin Peterson <benjamin@python.org>
parents: 51180
diff changeset
526 def _destinsrc(src, dst):
51180
5d0eaeb4134d Merged revisions 69101 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 48680
diff changeset
527 src = abspath(src)
5d0eaeb4134d Merged revisions 69101 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 48680
diff changeset
528 dst = abspath(dst)
5d0eaeb4134d Merged revisions 69101 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 48680
diff changeset
529 if not src.endswith(os.path.sep):
5d0eaeb4134d Merged revisions 69101 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 48680
diff changeset
530 src += os.path.sep
5d0eaeb4134d Merged revisions 69101 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 48680
diff changeset
531 if not dst.endswith(os.path.sep):
5d0eaeb4134d Merged revisions 69101 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 48680
diff changeset
532 dst += os.path.sep
5d0eaeb4134d Merged revisions 69101 via svnmerge from
Antoine Pitrou <solipsis@pitrou.net>
parents: 48680
diff changeset
533 return dst.startswith(src)
59056
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
534
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
535 def _get_gid(name):
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
536 """Returns a gid, given a group name."""
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
537 if getgrnam is None or name is None:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
538 return None
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
539 try:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
540 result = getgrnam(name)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
541 except KeyError:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
542 result = None
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
543 if result is not None:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
544 return result[2]
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
545 return None
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
546
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
547 def _get_uid(name):
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
548 """Returns an uid, given a user name."""
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
549 if getpwnam is None or name is None:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
550 return None
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
551 try:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
552 result = getpwnam(name)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
553 except KeyError:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
554 result = None
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
555 if result is not None:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
556 return result[2]
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
557 return None
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
558
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
559 def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
560 owner=None, group=None, logger=None):
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
561 """Create a (possibly compressed) tar file from all the files under
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
562 'base_dir'.
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
563
60789
bd45e0110990 Merged revisions 80282 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60770
diff changeset
564 'compress' must be "gzip" (the default), "bzip2", or None.
59056
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
565
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
566 'owner' and 'group' can be used to define an owner and a group for the
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
567 archive that is being built. If not provided, the current owner and group
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
568 will be used.
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
569
66932
2d2997f19e90 Fix wrong name in docstring and doc (#10693). Original patch by Eli Bendersky.
Éric Araujo <merwok@netwok.org>
parents: 61294
diff changeset
570 The output tar file will be named 'base_name' + ".tar", possibly plus
60789
bd45e0110990 Merged revisions 80282 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60770
diff changeset
571 the appropriate compression extension (".gz", or ".bz2").
59056
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
572
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
573 Returns the output filename.
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
574 """
61087
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
575 tar_compression = {'gzip': 'gz', None: ''}
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
576 compress_ext = {'gzip': '.gz'}
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
577
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
578 if _BZ2_SUPPORTED:
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
579 tar_compression['bzip2'] = 'bz2'
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
580 compress_ext['bzip2'] = '.bz2'
59056
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
581
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
582 # flags for compression program, each element of list will be an argument
72408
cc5e3a65e452 A few style changes originally done in the distutils2 repo
Éric Araujo <merwok@netwok.org>
parents: 72267
diff changeset
583 if compress is not None and compress not in compress_ext:
61087
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
584 raise ValueError("bad value for 'compress', or compression format not "
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
585 "supported : {0}".format(compress))
59056
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
586
60789
bd45e0110990 Merged revisions 80282 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60770
diff changeset
587 archive_name = base_name + '.tar' + compress_ext.get(compress, '')
bd45e0110990 Merged revisions 80282 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60770
diff changeset
588 archive_dir = os.path.dirname(archive_name)
59056
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
589
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
590 if not os.path.exists(archive_dir):
67804
5f1ad65a1b84 Protect logging call against None argument (fixes #11045).
Éric Araujo <merwok@netwok.org>
parents: 66932
diff changeset
591 if logger is not None:
71934
fe3b346fb09c Make logging call lazy
Éric Araujo <merwok@netwok.org>
parents: 69870
diff changeset
592 logger.info("creating %s", archive_dir)
59056
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
593 if not dry_run:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
594 os.makedirs(archive_dir)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
595
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
596 # creating the tarball
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
597 if logger is not None:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
598 logger.info('Creating tar archive')
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
599
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
600 uid = _get_uid(owner)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
601 gid = _get_gid(group)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
602
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
603 def _set_uid_gid(tarinfo):
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
604 if gid is not None:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
605 tarinfo.gid = gid
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
606 tarinfo.gname = group
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
607 if uid is not None:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
608 tarinfo.uid = uid
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
609 tarinfo.uname = owner
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
610 return tarinfo
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
611
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
612 if not dry_run:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
613 tar = tarfile.open(archive_name, 'w|%s' % tar_compression[compress])
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
614 try:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
615 tar.add(base_dir, filter=_set_uid_gid)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
616 finally:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
617 tar.close()
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
618
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
619 return archive_name
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
620
60810
c2905b0ef1d2 Merged revisions 80306 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60789
diff changeset
621 def _call_external_zip(base_dir, zip_filename, verbose=False, dry_run=False):
59056
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
622 # XXX see if we want to keep an external call here
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
623 if verbose:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
624 zipoptions = "-r"
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
625 else:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
626 zipoptions = "-rq"
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
627 from distutils.errors import DistutilsExecError
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
628 from distutils.spawn import spawn
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
629 try:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
630 spawn(["zip", zipoptions, zip_filename, base_dir], dry_run=dry_run)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
631 except DistutilsExecError:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
632 # XXX really should distinguish between "couldn't find
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
633 # external 'zip' command" and "zip failed".
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
634 raise ExecError("unable to create zip file '%s': "
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
635 "could neither import the 'zipfile' module nor "
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
636 "find a standalone zip utility") % zip_filename
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
637
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
638 def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None):
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
639 """Create a zip file from all the files under 'base_dir'.
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
640
66932
2d2997f19e90 Fix wrong name in docstring and doc (#10693). Original patch by Eli Bendersky.
Éric Araujo <merwok@netwok.org>
parents: 61294
diff changeset
641 The output zip file will be named 'base_name' + ".zip". Uses either the
59056
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
642 "zipfile" Python module (if available) or the InfoZIP "zip" utility
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
643 (if installed and found on the default search path). If neither tool is
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
644 available, raises ExecError. Returns the name of the output zip
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
645 file.
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
646 """
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
647 zip_filename = base_name + ".zip"
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
648 archive_dir = os.path.dirname(base_name)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
649
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
650 if not os.path.exists(archive_dir):
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
651 if logger is not None:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
652 logger.info("creating %s", archive_dir)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
653 if not dry_run:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
654 os.makedirs(archive_dir)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
655
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
656 # If zipfile module is not available, try spawning an external 'zip'
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
657 # command.
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
658 try:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
659 import zipfile
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
660 except ImportError:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
661 zipfile = None
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
662
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
663 if zipfile is None:
60810
c2905b0ef1d2 Merged revisions 80306 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60789
diff changeset
664 _call_external_zip(base_dir, zip_filename, verbose, dry_run)
59056
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
665 else:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
666 if logger is not None:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
667 logger.info("creating '%s' and adding '%s' to it",
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
668 zip_filename, base_dir)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
669
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
670 if not dry_run:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
671 zip = zipfile.ZipFile(zip_filename, "w",
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
672 compression=zipfile.ZIP_DEFLATED)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
673
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
674 for dirpath, dirnames, filenames in os.walk(base_dir):
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
675 for name in filenames:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
676 path = os.path.normpath(os.path.join(dirpath, name))
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
677 if os.path.isfile(path):
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
678 zip.write(path, path)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
679 if logger is not None:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
680 logger.info("adding '%s'", path)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
681 zip.close()
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
682
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
683 return zip_filename
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
684
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
685 _ARCHIVE_FORMATS = {
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
686 'gztar': (_make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"),
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
687 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"),
72408
cc5e3a65e452 A few style changes originally done in the distutils2 repo
Éric Araujo <merwok@netwok.org>
parents: 72267
diff changeset
688 'zip': (_make_zipfile, [], "ZIP file")
59056
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
689 }
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
690
61087
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
691 if _BZ2_SUPPORTED:
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
692 _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')],
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
693 "bzip2'ed tar-file")
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
694
59056
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
695 def get_archive_formats():
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
696 """Returns a list of supported formats for archiving and unarchiving.
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
697
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
698 Each element of the returned sequence is a tuple (name, description)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
699 """
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
700 formats = [(name, registry[2]) for name, registry in
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
701 _ARCHIVE_FORMATS.items()]
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
702 formats.sort()
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
703 return formats
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
704
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
705 def register_archive_format(name, function, extra_args=None, description=''):
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
706 """Registers an archive format.
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
707
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
708 name is the name of the format. function is the callable that will be
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
709 used to create archives. If provided, extra_args is a sequence of
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
710 (name, value) tuples that will be passed as arguments to the callable.
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
711 description can be provided to describe the format, and will be returned
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
712 by the get_archive_formats() function.
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
713 """
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
714 if extra_args is None:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
715 extra_args = []
73165
8e57b5d8f58f Closes #13258: Use callable() built-in in the standard library.
Florent Xicluna <florent.xicluna@gmail.com>
parents: 72265
diff changeset
716 if not callable(function):
59056
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
717 raise TypeError('The %s object is not callable' % function)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
718 if not isinstance(extra_args, (tuple, list)):
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
719 raise TypeError('extra_args needs to be a sequence')
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
720 for element in extra_args:
72408
cc5e3a65e452 A few style changes originally done in the distutils2 repo
Éric Araujo <merwok@netwok.org>
parents: 72267
diff changeset
721 if not isinstance(element, (tuple, list)) or len(element) !=2:
59056
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
722 raise TypeError('extra_args elements are : (arg_name, value)')
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
723
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
724 _ARCHIVE_FORMATS[name] = (function, extra_args, description)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
725
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
726 def unregister_archive_format(name):
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
727 del _ARCHIVE_FORMATS[name]
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
728
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
729 def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
730 dry_run=0, owner=None, group=None, logger=None):
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
731 """Create an archive file (eg. zip or tar).
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
732
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
733 'base_name' is the name of the file to create, minus any format-specific
60789
bd45e0110990 Merged revisions 80282 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60770
diff changeset
734 extension; 'format' is the archive format: one of "zip", "tar", "bztar"
bd45e0110990 Merged revisions 80282 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60770
diff changeset
735 or "gztar".
59056
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
736
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
737 'root_dir' is a directory that will be the root directory of the
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
738 archive; ie. we typically chdir into 'root_dir' before creating the
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
739 archive. 'base_dir' is the directory where we start archiving from;
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
740 ie. 'base_dir' will be the common prefix of all files and
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
741 directories in the archive. 'root_dir' and 'base_dir' both default
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
742 to the current directory. Returns the name of the archive file.
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
743
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
744 'owner' and 'group' are used when creating a tar archive. By default,
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
745 uses the current owner and group.
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
746 """
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
747 save_cwd = os.getcwd()
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
748 if root_dir is not None:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
749 if logger is not None:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
750 logger.debug("changing into '%s'", root_dir)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
751 base_name = os.path.abspath(base_name)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
752 if not dry_run:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
753 os.chdir(root_dir)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
754
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
755 if base_dir is None:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
756 base_dir = os.curdir
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
757
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
758 kwargs = {'dry_run': dry_run, 'logger': logger}
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
759
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
760 try:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
761 format_info = _ARCHIVE_FORMATS[format]
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
762 except KeyError:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
763 raise ValueError("unknown archive format '%s'" % format)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
764
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
765 func = format_info[0]
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
766 for arg, val in format_info[1]:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
767 kwargs[arg] = val
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
768
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
769 if format != 'zip':
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
770 kwargs['owner'] = owner
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
771 kwargs['group'] = group
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
772
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
773 try:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
774 filename = func(base_name, base_dir, **kwargs)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
775 finally:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
776 if root_dir is not None:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
777 if logger is not None:
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
778 logger.debug("changing back to '%s'", save_cwd)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
779 os.chdir(save_cwd)
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
780
a1d078b88247 Merged revisions 78359-78360 via svnmerge from
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 54594
diff changeset
781 return filename
61062
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
782
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
783
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
784 def get_unpack_formats():
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
785 """Returns a list of supported formats for unpacking.
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
786
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
787 Each element of the returned sequence is a tuple
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
788 (name, extensions, description)
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
789 """
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
790 formats = [(name, info[0], info[3]) for name, info in
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
791 _UNPACK_FORMATS.items()]
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
792 formats.sort()
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
793 return formats
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
794
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
795 def _check_unpack_options(extensions, function, extra_args):
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
796 """Checks what gets registered as an unpacker."""
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
797 # first make sure no other unpacker is registered for this extension
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
798 existing_extensions = {}
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
799 for name, info in _UNPACK_FORMATS.items():
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
800 for ext in info[0]:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
801 existing_extensions[ext] = name
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
802
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
803 for extension in extensions:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
804 if extension in existing_extensions:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
805 msg = '%s is already registered for "%s"'
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
806 raise RegistryError(msg % (extension,
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
807 existing_extensions[extension]))
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
808
73165
8e57b5d8f58f Closes #13258: Use callable() built-in in the standard library.
Florent Xicluna <florent.xicluna@gmail.com>
parents: 72265
diff changeset
809 if not callable(function):
61062
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
810 raise TypeError('The registered function must be a callable')
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
811
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
812
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
813 def register_unpack_format(name, extensions, function, extra_args=None,
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
814 description=''):
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
815 """Registers an unpack format.
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
816
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
817 `name` is the name of the format. `extensions` is a list of extensions
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
818 corresponding to the format.
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
819
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
820 `function` is the callable that will be
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
821 used to unpack archives. The callable will receive archives to unpack.
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
822 If it's unable to handle an archive, it needs to raise a ReadError
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
823 exception.
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
824
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
825 If provided, `extra_args` is a sequence of
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
826 (name, value) tuples that will be passed as arguments to the callable.
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
827 description can be provided to describe the format, and will be returned
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
828 by the get_unpack_formats() function.
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
829 """
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
830 if extra_args is None:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
831 extra_args = []
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
832 _check_unpack_options(extensions, function, extra_args)
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
833 _UNPACK_FORMATS[name] = extensions, function, extra_args, description
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
834
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
835 def unregister_unpack_format(name):
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
836 """Removes the pack format from the registery."""
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
837 del _UNPACK_FORMATS[name]
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
838
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
839 def _ensure_directory(path):
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
840 """Ensure that the parent directory of `path` exists"""
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
841 dirname = os.path.dirname(path)
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
842 if not os.path.isdir(dirname):
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
843 os.makedirs(dirname)
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
844
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
845 def _unpack_zipfile(filename, extract_dir):
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
846 """Unpack zip `filename` to `extract_dir`
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
847 """
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
848 try:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
849 import zipfile
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
850 except ImportError:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
851 raise ReadError('zlib not supported, cannot unpack this archive.')
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
852
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
853 if not zipfile.is_zipfile(filename):
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
854 raise ReadError("%s is not a zip file" % filename)
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
855
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
856 zip = zipfile.ZipFile(filename)
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
857 try:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
858 for info in zip.infolist():
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
859 name = info.filename
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
860
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
861 # don't extract absolute paths or ones with .. in them
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
862 if name.startswith('/') or '..' in name:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
863 continue
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
864
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
865 target = os.path.join(extract_dir, *name.split('/'))
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
866 if not target:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
867 continue
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
868
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
869 _ensure_directory(target)
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
870 if not name.endswith('/'):
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
871 # file
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
872 data = zip.read(info.filename)
72408
cc5e3a65e452 A few style changes originally done in the distutils2 repo
Éric Araujo <merwok@netwok.org>
parents: 72267
diff changeset
873 f = open(target, 'wb')
61062
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
874 try:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
875 f.write(data)
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
876 finally:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
877 f.close()
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
878 del data
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
879 finally:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
880 zip.close()
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
881
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
882 def _unpack_tarfile(filename, extract_dir):
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
883 """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir`
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
884 """
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
885 try:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
886 tarobj = tarfile.open(filename)
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
887 except tarfile.TarError:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
888 raise ReadError(
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
889 "%s is not a compressed or uncompressed tar file" % filename)
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
890 try:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
891 tarobj.extractall(extract_dir)
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
892 finally:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
893 tarobj.close()
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
894
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
895 _UNPACK_FORMATS = {
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
896 'gztar': (['.tar.gz', '.tgz'], _unpack_tarfile, [], "gzip'ed tar-file"),
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
897 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"),
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
898 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file")
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
899 }
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
900
61087
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
901 if _BZ2_SUPPORTED:
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
902 _UNPACK_FORMATS['bztar'] = (['.bz2'], _unpack_tarfile, [],
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
903 "bzip2'ed tar-file")
4b57019150a8 make sure shutil checks for bz2 availability before it uses it.
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 61062
diff changeset
904
61062
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
905 def _find_unpack_format(filename):
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
906 for name, info in _UNPACK_FORMATS.items():
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
907 for extension in info[0]:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
908 if filename.endswith(extension):
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
909 return name
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
910 return None
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
911
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
912 def unpack_archive(filename, extract_dir=None, format=None):
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
913 """Unpack an archive.
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
914
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
915 `filename` is the name of the archive.
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
916
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
917 `extract_dir` is the name of the target directory, where the archive
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
918 is unpacked. If not provided, the current working directory is used.
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
919
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
920 `format` is the archive format: one of "zip", "tar", or "gztar". Or any
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
921 other registered format. If not provided, unpack_archive will use the
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
922 filename extension and see if an unpacker was registered for that
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
923 extension.
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
924
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
925 In case none is found, a ValueError is raised.
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
926 """
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
927 if extract_dir is None:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
928 extract_dir = os.getcwd()
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
929
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
930 if format is not None:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
931 try:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
932 format_info = _UNPACK_FORMATS[format]
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
933 except KeyError:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
934 raise ValueError("Unknown unpack format '{0}'".format(format))
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
935
68601
d1619747c17d Close #11548: Correctly handle format argument in shutil.unpack_archive
Nick Coghlan <ncoghlan@gmail.com>
parents: 68257
diff changeset
936 func = format_info[1]
d1619747c17d Close #11548: Correctly handle format argument in shutil.unpack_archive
Nick Coghlan <ncoghlan@gmail.com>
parents: 68257
diff changeset
937 func(filename, extract_dir, **dict(format_info[2]))
61062
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
938 else:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
939 # we need to look at the registered unpackers supported extensions
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
940 format = _find_unpack_format(filename)
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
941 if format is None:
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
942 raise ReadError("Unknown archive format '{0}'".format(filename))
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
943
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
944 func = _UNPACK_FORMATS[format][1]
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
945 kwargs = dict(_UNPACK_FORMATS[format][2])
a43776553ab5 #8295 : Added shutil.unpack_archive and related APIs
Tarek Ziadé <ziade.tarek@gmail.com>
parents: 60892
diff changeset
946 func(filename, extract_dir, **kwargs)
71110
2fc102ebaf73 Issue #12442: add shutil.disk_usage()
Giampaolo Rodola' <g.rodola@gmail.com>
parents: 69870
diff changeset
947
71781
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
948
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
949 if hasattr(os, 'statvfs'):
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
950
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
951 __all__.append('disk_usage')
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
952 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
71110
2fc102ebaf73 Issue #12442: add shutil.disk_usage()
Giampaolo Rodola' <g.rodola@gmail.com>
parents: 69870
diff changeset
953
2fc102ebaf73 Issue #12442: add shutil.disk_usage()
Giampaolo Rodola' <g.rodola@gmail.com>
parents: 69870
diff changeset
954 def disk_usage(path):
71781
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
955 """Return disk usage statistics about the given path.
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
956
76505
629d4c2faa87 Issue #14650: fix typo in shutil.disk_usage() docstring; patch by Hobson Lane
Sandro Tosi <sandro.tosi@gmail.com>
parents: 74835
diff changeset
957 Returned value is a named tuple with attributes 'total', 'used' and
71781
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
958 'free', which are the amount of total, used and free space, in bytes.
71110
2fc102ebaf73 Issue #12442: add shutil.disk_usage()
Giampaolo Rodola' <g.rodola@gmail.com>
parents: 69870
diff changeset
959 """
71781
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
960 st = os.statvfs(path)
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
961 free = st.f_bavail * st.f_frsize
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
962 total = st.f_blocks * st.f_frsize
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
963 used = (st.f_blocks - st.f_bfree) * st.f_frsize
71110
2fc102ebaf73 Issue #12442: add shutil.disk_usage()
Giampaolo Rodola' <g.rodola@gmail.com>
parents: 69870
diff changeset
964 return _ntuple_diskusage(total, used, free)
71781
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
965
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
966 elif os.name == 'nt':
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
967
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
968 import nt
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
969 __all__.append('disk_usage')
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
970 _ntuple_diskusage = collections.namedtuple('usage', 'total used free')
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
971
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
972 def disk_usage(path):
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
973 """Return disk usage statistics about the given path.
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
974
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
975 Returned valus is a named tuple with attributes 'total', 'used' and
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
976 'free', which are the amount of total, used and free space, in bytes.
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
977 """
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
978 total, free = nt._getdiskusage(path)
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
979 used = total - free
f1e761dea2ee Clean up shutil.disk_usage.
Éric Araujo <merwok@netwok.org>
parents: 71110
diff changeset
980 return _ntuple_diskusage(total, used, free)
72039
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
981
72182
b166dc85f604 Add missing name in shutil.__all__
Éric Araujo <merwok@netwok.org>
parents: 72039
diff changeset
982
72039
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
983 def chown(path, user=None, group=None):
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
984 """Change owner user and group of the given path.
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
985
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
986 user and group can be the uid/gid or the user/group names, and in that case,
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
987 they are converted to their respective uid/gid.
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
988 """
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
989
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
990 if user is None and group is None:
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
991 raise ValueError("user and/or group must be set")
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
992
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
993 _user = user
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
994 _group = group
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
995
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
996 # -1 means don't change it
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
997 if user is None:
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
998 _user = -1
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
999 # user can either be an int (the uid) or a string (the system username)
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
1000 elif isinstance(user, str):
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
1001 _user = _get_uid(user)
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
1002 if _user is None:
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
1003 raise LookupError("no such user: {!r}".format(user))
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
1004
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
1005 if group is None:
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
1006 _group = -1
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
1007 elif not isinstance(group, int):
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
1008 _group = _get_gid(group)
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
1009 if _group is None:
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
1010 raise LookupError("no such group: {!r}".format(group))
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
1011
d1fd0f0f8e68 #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.
Sandro Tosi <sandro.tosi@gmail.com>
parents: 72017
diff changeset
1012 os.chown(path, _user, _group)
74835
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1013
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1014 def get_terminal_size(fallback=(80, 24)):
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1015 """Get the size of the terminal window.
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1016
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1017 For each of the two dimensions, the environment variable, COLUMNS
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1018 and LINES respectively, is checked. If the variable is defined and
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1019 the value is a positive integer, it is used.
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1020
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1021 When COLUMNS or LINES is not defined, which is the common case,
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1022 the terminal connected to sys.__stdout__ is queried
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1023 by invoking os.get_terminal_size.
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1024
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1025 If the terminal size cannot be successfully queried, either because
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1026 the system doesn't support querying, or because we are not
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1027 connected to a terminal, the value given in fallback parameter
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1028 is used. Fallback defaults to (80, 24) which is the default
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1029 size used by many terminal emulators.
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1030
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1031 The value returned is a named tuple of type os.terminal_size.
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1032 """
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1033 # columns, lines are the working values
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1034 try:
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1035 columns = int(os.environ['COLUMNS'])
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1036 except (KeyError, ValueError):
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1037 columns = 0
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1038
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1039 try:
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1040 lines = int(os.environ['LINES'])
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1041 except (KeyError, ValueError):
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1042 lines = 0
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1043
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1044 # only query if necessary
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1045 if columns <= 0 or lines <= 0:
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1046 try:
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1047 size = os.get_terminal_size(sys.__stdout__.fileno())
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1048 except (NameError, OSError):
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1049 size = os.terminal_size(fallback)
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1050 if columns <= 0:
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1051 columns = size.columns
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1052 if lines <= 0:
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1053 lines = size.lines
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1054
c92f8de398ed Issue #13609: Add two functions to query the terminal size:
Antoine Pitrou <solipsis@pitrou.net>
parents: 74793
diff changeset
1055 return os.terminal_size((columns, lines))
77588
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1056
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1057 def which(cmd, mode=os.F_OK | os.X_OK, path=None):
77610
aa153b827d17 Fix #15148. Capitalize PATH, hopefully leading to less confusion
Brian Curtin <brian@python.org>
parents: 77609
diff changeset
1058 """Given a command, mode, and a PATH string, return the path which
77660
48623d846f80 small refactor and PEP8 line width/docstring
Philip Jenvey <pjenvey@underboss.org>
parents: 77642
diff changeset
1059 conforms to the given mode on the PATH, or None if there is no such
48623d846f80 small refactor and PEP8 line width/docstring
Philip Jenvey <pjenvey@underboss.org>
parents: 77642
diff changeset
1060 file.
48623d846f80 small refactor and PEP8 line width/docstring
Philip Jenvey <pjenvey@underboss.org>
parents: 77642
diff changeset
1061
48623d846f80 small refactor and PEP8 line width/docstring
Philip Jenvey <pjenvey@underboss.org>
parents: 77642
diff changeset
1062 `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
48623d846f80 small refactor and PEP8 line width/docstring
Philip Jenvey <pjenvey@underboss.org>
parents: 77642
diff changeset
1063 of os.environ.get("PATH"), or can be overridden with a custom search
48623d846f80 small refactor and PEP8 line width/docstring
Philip Jenvey <pjenvey@underboss.org>
parents: 77642
diff changeset
1064 path.
48623d846f80 small refactor and PEP8 line width/docstring
Philip Jenvey <pjenvey@underboss.org>
parents: 77642
diff changeset
1065
48623d846f80 small refactor and PEP8 line width/docstring
Philip Jenvey <pjenvey@underboss.org>
parents: 77642
diff changeset
1066 """
77588
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1067 # Check that a given file can be accessed with the correct mode.
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1068 # Additionally check that `file` is not a directory, as on Windows
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1069 # directories pass the os.access check.
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1070 def _access_check(fn, mode):
77660
48623d846f80 small refactor and PEP8 line width/docstring
Philip Jenvey <pjenvey@underboss.org>
parents: 77642
diff changeset
1071 return (os.path.exists(fn) and os.access(fn, mode)
48623d846f80 small refactor and PEP8 line width/docstring
Philip Jenvey <pjenvey@underboss.org>
parents: 77642
diff changeset
1072 and not os.path.isdir(fn))
77588
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1073
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1074 # Short circuit. If we're given a full path which matches the mode
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1075 # and it exists, we're done here.
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1076 if _access_check(cmd, mode):
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1077 return cmd
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1078
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1079 path = (path or os.environ.get("PATH", os.defpath)).split(os.pathsep)
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1080
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1081 if sys.platform == "win32":
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1082 # The current directory takes precedence on Windows.
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1083 if not os.curdir in path:
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1084 path.insert(0, os.curdir)
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1085
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1086 # PATHEXT is necessary to check on Windows.
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1087 pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1088 # See if the given file matches any of the expected path extensions.
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1089 # This will allow us to short circuit when given "python.exe".
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1090 matches = [cmd for ext in pathext if cmd.lower().endswith(ext.lower())]
77660
48623d846f80 small refactor and PEP8 line width/docstring
Philip Jenvey <pjenvey@underboss.org>
parents: 77642
diff changeset
1091 # If it does match, only test that one, otherwise we have to try
48623d846f80 small refactor and PEP8 line width/docstring
Philip Jenvey <pjenvey@underboss.org>
parents: 77642
diff changeset
1092 # others.
48623d846f80 small refactor and PEP8 line width/docstring
Philip Jenvey <pjenvey@underboss.org>
parents: 77642
diff changeset
1093 files = [cmd] if matches else [cmd + ext.lower() for ext in pathext]
77588
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1094 else:
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1095 # On other platforms you don't have things like PATHEXT to tell you
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1096 # what file suffixes are executable, so just pass on cmd as-is.
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1097 files = [cmd]
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1098
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1099 seen = set()
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1100 for dir in path:
77590
9d2fe615a400 Issue #444582: shutil.which() respects relative paths.
Antoine Pitrou <solipsis@pitrou.net>
parents: 77589
diff changeset
1101 dir = os.path.normcase(dir)
77588
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1102 if not dir in seen:
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1103 seen.add(dir)
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1104 for thefile in files:
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1105 name = os.path.join(dir, thefile)
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1106 if _access_check(name, mode):
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1107 return name
0fe7439e470c Fix #444582. Add shutil.which function for finding programs on the system path.
Brian Curtin <brian@python.org>
parents: 77514
diff changeset
1108 return None