Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(768)

Side by Side Diff: recipe_engine/third_party/setuptools/archive_util.py

Issue 1344583003: Recipe package system. (Closed) Base URL: git@github.com:luci/recipes-py.git@master
Patch Set: Recompiled proto Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 """Utilities for extracting common archive formats"""
2
3
4 __all__ = [
5 "unpack_archive", "unpack_zipfile", "unpack_tarfile", "default_filter",
6 "UnrecognizedFormat", "extraction_drivers", "unpack_directory",
7 ]
8
9 import zipfile
10 import tarfile
11 import os
12 import shutil
13 import posixpath
14 import contextlib
15 from pkg_resources import ensure_directory, ContextualZipFile
16 from distutils.errors import DistutilsError
17
18 class UnrecognizedFormat(DistutilsError):
19 """Couldn't recognize the archive type"""
20
21 def default_filter(src,dst):
22 """The default progress/filter callback; returns True for all files"""
23 return dst
24
25
26 def unpack_archive(filename, extract_dir, progress_filter=default_filter,
27 drivers=None):
28 """Unpack `filename` to `extract_dir`, or raise ``UnrecognizedFormat``
29
30 `progress_filter` is a function taking two arguments: a source path
31 internal to the archive ('/'-separated), and a filesystem path where it
32 will be extracted. The callback must return the desired extract path
33 (which may be the same as the one passed in), or else ``None`` to skip
34 that file or directory. The callback can thus be used to report on the
35 progress of the extraction, as well as to filter the items extracted or
36 alter their extraction paths.
37
38 `drivers`, if supplied, must be a non-empty sequence of functions with the
39 same signature as this function (minus the `drivers` argument), that raise
40 ``UnrecognizedFormat`` if they do not support extracting the designated
41 archive type. The `drivers` are tried in sequence until one is found that
42 does not raise an error, or until all are exhausted (in which case
43 ``UnrecognizedFormat`` is raised). If you do not supply a sequence of
44 drivers, the module's ``extraction_drivers`` constant will be used, which
45 means that ``unpack_zipfile`` and ``unpack_tarfile`` will be tried, in that
46 order.
47 """
48 for driver in drivers or extraction_drivers:
49 try:
50 driver(filename, extract_dir, progress_filter)
51 except UnrecognizedFormat:
52 continue
53 else:
54 return
55 else:
56 raise UnrecognizedFormat(
57 "Not a recognized archive type: %s" % filename
58 )
59
60
61 def unpack_directory(filename, extract_dir, progress_filter=default_filter):
62 """"Unpack" a directory, using the same interface as for archives
63
64 Raises ``UnrecognizedFormat`` if `filename` is not a directory
65 """
66 if not os.path.isdir(filename):
67 raise UnrecognizedFormat("%s is not a directory" % (filename,))
68
69 paths = {filename:('',extract_dir)}
70 for base, dirs, files in os.walk(filename):
71 src,dst = paths[base]
72 for d in dirs:
73 paths[os.path.join(base,d)] = src+d+'/', os.path.join(dst,d)
74 for f in files:
75 target = os.path.join(dst,f)
76 target = progress_filter(src+f, target)
77 if not target:
78 continue # skip non-files
79 ensure_directory(target)
80 f = os.path.join(base,f)
81 shutil.copyfile(f, target)
82 shutil.copystat(f, target)
83
84
85 def unpack_zipfile(filename, extract_dir, progress_filter=default_filter):
86 """Unpack zip `filename` to `extract_dir`
87
88 Raises ``UnrecognizedFormat`` if `filename` is not a zipfile (as determined
89 by ``zipfile.is_zipfile()``). See ``unpack_archive()`` for an explanation
90 of the `progress_filter` argument.
91 """
92
93 if not zipfile.is_zipfile(filename):
94 raise UnrecognizedFormat("%s is not a zip file" % (filename,))
95
96 with ContextualZipFile(filename) as z:
97 for info in z.infolist():
98 name = info.filename
99
100 # don't extract absolute paths or ones with .. in them
101 if name.startswith('/') or '..' in name.split('/'):
102 continue
103
104 target = os.path.join(extract_dir, *name.split('/'))
105 target = progress_filter(name, target)
106 if not target:
107 continue
108 if name.endswith('/'):
109 # directory
110 ensure_directory(target)
111 else:
112 # file
113 ensure_directory(target)
114 data = z.read(info.filename)
115 f = open(target,'wb')
116 try:
117 f.write(data)
118 finally:
119 f.close()
120 del data
121 unix_attributes = info.external_attr >> 16
122 if unix_attributes:
123 os.chmod(target, unix_attributes)
124
125
126 def unpack_tarfile(filename, extract_dir, progress_filter=default_filter):
127 """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir`
128
129 Raises ``UnrecognizedFormat`` if `filename` is not a tarfile (as determined
130 by ``tarfile.open()``). See ``unpack_archive()`` for an explanation
131 of the `progress_filter` argument.
132 """
133 try:
134 tarobj = tarfile.open(filename)
135 except tarfile.TarError:
136 raise UnrecognizedFormat(
137 "%s is not a compressed or uncompressed tar file" % (filename,)
138 )
139 with contextlib.closing(tarobj):
140 tarobj.chown = lambda *args: None # don't do any chowning!
141 for member in tarobj:
142 name = member.name
143 # don't extract absolute paths or ones with .. in them
144 if not name.startswith('/') and '..' not in name.split('/'):
145 prelim_dst = os.path.join(extract_dir, *name.split('/'))
146
147 # resolve any links and to extract the link targets as normal fi les
148 while member is not None and (member.islnk() or member.issym()):
149 linkpath = member.linkname
150 if member.issym():
151 linkpath = posixpath.join(posixpath.dirname(member.name) , linkpath)
152 linkpath = posixpath.normpath(linkpath)
153 member = tarobj._getmember(linkpath)
154
155 if member is not None and (member.isfile() or member.isdir()):
156 final_dst = progress_filter(name, prelim_dst)
157 if final_dst:
158 if final_dst.endswith(os.sep):
159 final_dst = final_dst[:-1]
160 try:
161 tarobj._extract_member(member, final_dst) # XXX Ugh
162 except tarfile.ExtractError:
163 pass # chown/chmod/mkfifo/mknode/makedev failed
164 return True
165
166 extraction_drivers = unpack_directory, unpack_zipfile, unpack_tarfile
OLDNEW
« no previous file with comments | « recipe_engine/third_party/setuptools/_vendor/packaging/version.py ('k') | recipe_engine/third_party/setuptools/cli.exe » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698