ยปCore Development>Code coverage>Lib/distutils/archive_util.py

Python code coverage for Lib/distutils/archive_util.py

#countcontent
1n/a"""distutils.archive_util
2n/a
3n/aUtility functions for creating archive files (tarballs, zip files,
4n/athat sort of thing)."""
5n/a
6n/aimport os
7n/afrom warnings import warn
8n/aimport sys
9n/a
10n/atry:
11n/a import zipfile
12n/aexcept ImportError:
13n/a zipfile = None
14n/a
15n/a
16n/afrom distutils.errors import DistutilsExecError
17n/afrom distutils.spawn import spawn
18n/afrom distutils.dir_util import mkpath
19n/afrom distutils import log
20n/a
21n/atry:
22n/a from pwd import getpwnam
23n/aexcept ImportError:
24n/a getpwnam = None
25n/a
26n/atry:
27n/a from grp import getgrnam
28n/aexcept ImportError:
29n/a getgrnam = None
30n/a
31n/adef _get_gid(name):
32n/a """Returns a gid, given a group name."""
33n/a if getgrnam is None or name is None:
34n/a return None
35n/a try:
36n/a result = getgrnam(name)
37n/a except KeyError:
38n/a result = None
39n/a if result is not None:
40n/a return result[2]
41n/a return None
42n/a
43n/adef _get_uid(name):
44n/a """Returns an uid, given a user name."""
45n/a if getpwnam is None or name is None:
46n/a return None
47n/a try:
48n/a result = getpwnam(name)
49n/a except KeyError:
50n/a result = None
51n/a if result is not None:
52n/a return result[2]
53n/a return None
54n/a
55n/adef make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
56n/a owner=None, group=None):
57n/a """Create a (possibly compressed) tar file from all the files under
58n/a 'base_dir'.
59n/a
60n/a 'compress' must be "gzip" (the default), "bzip2", "xz", "compress", or
61n/a None. ("compress" will be deprecated in Python 3.2)
62n/a
63n/a 'owner' and 'group' can be used to define an owner and a group for the
64n/a archive that is being built. If not provided, the current owner and group
65n/a will be used.
66n/a
67n/a The output tar file will be named 'base_dir' + ".tar", possibly plus
68n/a the appropriate compression extension (".gz", ".bz2", ".xz" or ".Z").
69n/a
70n/a Returns the output filename.
71n/a """
72n/a tar_compression = {'gzip': 'gz', 'bzip2': 'bz2', 'xz': 'xz', None: '',
73n/a 'compress': ''}
74n/a compress_ext = {'gzip': '.gz', 'bzip2': '.bz2', 'xz': '.xz',
75n/a 'compress': '.Z'}
76n/a
77n/a # flags for compression program, each element of list will be an argument
78n/a if compress is not None and compress not in compress_ext.keys():
79n/a raise ValueError(
80n/a "bad value for 'compress': must be None, 'gzip', 'bzip2', "
81n/a "'xz' or 'compress'")
82n/a
83n/a archive_name = base_name + '.tar'
84n/a if compress != 'compress':
85n/a archive_name += compress_ext.get(compress, '')
86n/a
87n/a mkpath(os.path.dirname(archive_name), dry_run=dry_run)
88n/a
89n/a # creating the tarball
90n/a import tarfile # late import so Python build itself doesn't break
91n/a
92n/a log.info('Creating tar archive')
93n/a
94n/a uid = _get_uid(owner)
95n/a gid = _get_gid(group)
96n/a
97n/a def _set_uid_gid(tarinfo):
98n/a if gid is not None:
99n/a tarinfo.gid = gid
100n/a tarinfo.gname = group
101n/a if uid is not None:
102n/a tarinfo.uid = uid
103n/a tarinfo.uname = owner
104n/a return tarinfo
105n/a
106n/a if not dry_run:
107n/a tar = tarfile.open(archive_name, 'w|%s' % tar_compression[compress])
108n/a try:
109n/a tar.add(base_dir, filter=_set_uid_gid)
110n/a finally:
111n/a tar.close()
112n/a
113n/a # compression using `compress`
114n/a if compress == 'compress':
115n/a warn("'compress' will be deprecated.", PendingDeprecationWarning)
116n/a # the option varies depending on the platform
117n/a compressed_name = archive_name + compress_ext[compress]
118n/a if sys.platform == 'win32':
119n/a cmd = [compress, archive_name, compressed_name]
120n/a else:
121n/a cmd = [compress, '-f', archive_name]
122n/a spawn(cmd, dry_run=dry_run)
123n/a return compressed_name
124n/a
125n/a return archive_name
126n/a
127n/adef make_zipfile(base_name, base_dir, verbose=0, dry_run=0):
128n/a """Create a zip file from all the files under 'base_dir'.
129n/a
130n/a The output zip file will be named 'base_name' + ".zip". Uses either the
131n/a "zipfile" Python module (if available) or the InfoZIP "zip" utility
132n/a (if installed and found on the default search path). If neither tool is
133n/a available, raises DistutilsExecError. Returns the name of the output zip
134n/a file.
135n/a """
136n/a zip_filename = base_name + ".zip"
137n/a mkpath(os.path.dirname(zip_filename), dry_run=dry_run)
138n/a
139n/a # If zipfile module is not available, try spawning an external
140n/a # 'zip' command.
141n/a if zipfile is None:
142n/a if verbose:
143n/a zipoptions = "-r"
144n/a else:
145n/a zipoptions = "-rq"
146n/a
147n/a try:
148n/a spawn(["zip", zipoptions, zip_filename, base_dir],
149n/a dry_run=dry_run)
150n/a except DistutilsExecError:
151n/a # XXX really should distinguish between "couldn't find
152n/a # external 'zip' command" and "zip failed".
153n/a raise DistutilsExecError(("unable to create zip file '%s': "
154n/a "could neither import the 'zipfile' module nor "
155n/a "find a standalone zip utility") % zip_filename)
156n/a
157n/a else:
158n/a log.info("creating '%s' and adding '%s' to it",
159n/a zip_filename, base_dir)
160n/a
161n/a if not dry_run:
162n/a try:
163n/a zip = zipfile.ZipFile(zip_filename, "w",
164n/a compression=zipfile.ZIP_DEFLATED)
165n/a except RuntimeError:
166n/a zip = zipfile.ZipFile(zip_filename, "w",
167n/a compression=zipfile.ZIP_STORED)
168n/a
169n/a for dirpath, dirnames, filenames in os.walk(base_dir):
170n/a for name in filenames:
171n/a path = os.path.normpath(os.path.join(dirpath, name))
172n/a if os.path.isfile(path):
173n/a zip.write(path, path)
174n/a log.info("adding '%s'", path)
175n/a zip.close()
176n/a
177n/a return zip_filename
178n/a
179n/aARCHIVE_FORMATS = {
180n/a 'gztar': (make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"),
181n/a 'bztar': (make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"),
182n/a 'xztar': (make_tarball, [('compress', 'xz')], "xz'ed tar-file"),
183n/a 'ztar': (make_tarball, [('compress', 'compress')], "compressed tar file"),
184n/a 'tar': (make_tarball, [('compress', None)], "uncompressed tar file"),
185n/a 'zip': (make_zipfile, [],"ZIP file")
186n/a }
187n/a
188n/adef check_archive_formats(formats):
189n/a """Returns the first format from the 'format' list that is unknown.
190n/a
191n/a If all formats are known, returns None
192n/a """
193n/a for format in formats:
194n/a if format not in ARCHIVE_FORMATS:
195n/a return format
196n/a return None
197n/a
198n/adef make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
199n/a dry_run=0, owner=None, group=None):
200n/a """Create an archive file (eg. zip or tar).
201n/a
202n/a 'base_name' is the name of the file to create, minus any format-specific
203n/a extension; 'format' is the archive format: one of "zip", "tar", "gztar",
204n/a "bztar", "xztar", or "ztar".
205n/a
206n/a 'root_dir' is a directory that will be the root directory of the
207n/a archive; ie. we typically chdir into 'root_dir' before creating the
208n/a archive. 'base_dir' is the directory where we start archiving from;
209n/a ie. 'base_dir' will be the common prefix of all files and
210n/a directories in the archive. 'root_dir' and 'base_dir' both default
211n/a to the current directory. Returns the name of the archive file.
212n/a
213n/a 'owner' and 'group' are used when creating a tar archive. By default,
214n/a uses the current owner and group.
215n/a """
216n/a save_cwd = os.getcwd()
217n/a if root_dir is not None:
218n/a log.debug("changing into '%s'", root_dir)
219n/a base_name = os.path.abspath(base_name)
220n/a if not dry_run:
221n/a os.chdir(root_dir)
222n/a
223n/a if base_dir is None:
224n/a base_dir = os.curdir
225n/a
226n/a kwargs = {'dry_run': dry_run}
227n/a
228n/a try:
229n/a format_info = ARCHIVE_FORMATS[format]
230n/a except KeyError:
231n/a raise ValueError("unknown archive format '%s'" % format)
232n/a
233n/a func = format_info[0]
234n/a for arg, val in format_info[1]:
235n/a kwargs[arg] = val
236n/a
237n/a if format != 'zip':
238n/a kwargs['owner'] = owner
239n/a kwargs['group'] = group
240n/a
241n/a try:
242n/a filename = func(base_name, base_dir, **kwargs)
243n/a finally:
244n/a if root_dir is not None:
245n/a log.debug("changing back to '%s'", save_cwd)
246n/a os.chdir(save_cwd)
247n/a
248n/a return filename