blob: 9444ff012fb937cdfd99e031acd018f82c18f122 [file] [log] [blame]
Greg Wardaebf7062000-04-04 02:05:59 +00001"""distutils.archive_util
2
3Utility functions for creating archive files (tarballs, zip files,
4that sort of thing)."""
5
Greg Wardaebf7062000-04-04 02:05:59 +00006__revision__ = "$Id$"
7
8import os
9from distutils.errors import DistutilsExecError
10from distutils.spawn import spawn
Greg Ward04e25a12000-08-22 01:48:54 +000011from distutils.dir_util import mkpath
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +000012from distutils import log
Greg Wardaebf7062000-04-04 02:05:59 +000013
14def make_tarball (base_name, base_dir, compress="gzip",
15 verbose=0, dry_run=0):
16 """Create a (possibly compressed) tar file from all the files under
Greg Wardca4289f2000-09-26 02:13:49 +000017 'base_dir'. 'compress' must be "gzip" (the default), "compress",
18 "bzip2", or None. Both "tar" and the compression utility named by
19 'compress' must be on the default program search path, so this is
20 probably Unix-specific. The output tar file will be named 'base_dir' +
21 ".tar", possibly plus the appropriate compression extension (".gz",
22 ".bz2" or ".Z"). Return the output filename.
23 """
Greg Wardaebf7062000-04-04 02:05:59 +000024 # XXX GNU tar 1.13 has a nifty option to add a prefix directory.
25 # It's pretty new, though, so we certainly can't require it --
26 # but it would be nice to take advantage of it to skip the
27 # "create a tree of hardlinks" step! (Would also be nice to
28 # detect GNU tar to use its 'z' option and save a step.)
29
30 compress_ext = { 'gzip': ".gz",
Greg Wardf1948782000-04-25 01:38:20 +000031 'bzip2': '.bz2',
Greg Wardaebf7062000-04-04 02:05:59 +000032 'compress': ".Z" }
Fred Drakeb94b8492001-12-06 20:51:35 +000033
Greg Wardf1948782000-04-25 01:38:20 +000034 # flags for compression program, each element of list will be an argument
35 compress_flags = {'gzip': ["-f9"],
36 'compress': ["-f"],
37 'bzip2': ['-f9']}
Greg Wardaebf7062000-04-04 02:05:59 +000038
Greg Wardf1948782000-04-25 01:38:20 +000039 if compress is not None and compress not in compress_ext.keys():
Collin Winter5b7e9d72007-08-30 03:52:21 +000040 raise ValueError(
41 "bad value for 'compress': must be None, 'gzip', or 'compress'")
Greg Wardaebf7062000-04-04 02:05:59 +000042
43 archive_name = base_name + ".tar"
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +000044 mkpath(os.path.dirname(archive_name), dry_run=dry_run)
Greg Wardaebf7062000-04-04 02:05:59 +000045 cmd = ["tar", "-cf", archive_name, base_dir]
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +000046 spawn(cmd, dry_run=dry_run)
Greg Wardaebf7062000-04-04 02:05:59 +000047
48 if compress:
Greg Wardca4289f2000-09-26 02:13:49 +000049 spawn([compress] + compress_flags[compress] + [archive_name],
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +000050 dry_run=dry_run)
Greg Wardaebf7062000-04-04 02:05:59 +000051 return archive_name + compress_ext[compress]
52 else:
53 return archive_name
54
55# make_tarball ()
56
57
58def make_zipfile (base_name, base_dir, verbose=0, dry_run=0):
Greg Wardca4289f2000-09-26 02:13:49 +000059 """Create a zip file from all the files under 'base_dir'. The output
Andrew M. Kuchlingcdd21572002-11-21 18:33:28 +000060 zip file will be named 'base_dir' + ".zip". Uses either the "zipfile"
61 Python module (if available) or the InfoZIP "zip" utility (if installed
62 and found on the default search path). If neither tool is available,
63 raises DistutilsExecError. Returns the name of the output zip file.
Greg Wardca4289f2000-09-26 02:13:49 +000064 """
Andrew M. Kuchlingcdd21572002-11-21 18:33:28 +000065 try:
66 import zipfile
67 except ImportError:
68 zipfile = None
Tim Peters182b5ac2004-07-18 06:16:08 +000069
Greg Wardaebf7062000-04-04 02:05:59 +000070 zip_filename = base_name + ".zip"
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +000071 mkpath(os.path.dirname(zip_filename), dry_run=dry_run)
Greg Wardaebf7062000-04-04 02:05:59 +000072
Andrew M. Kuchlingcdd21572002-11-21 18:33:28 +000073 # If zipfile module is not available, try spawning an external
74 # 'zip' command.
75 if zipfile is None:
76 if verbose:
77 zipoptions = "-r"
78 else:
79 zipoptions = "-rq"
Tim Peters182b5ac2004-07-18 06:16:08 +000080
Andrew M. Kuchlingcdd21572002-11-21 18:33:28 +000081 try:
82 spawn(["zip", zipoptions, zip_filename, base_dir],
83 dry_run=dry_run)
84 except DistutilsExecError:
85 # XXX really should distinguish between "couldn't find
86 # external 'zip' command" and "zip failed".
Collin Winter5b7e9d72007-08-30 03:52:21 +000087 raise DistutilsExecError(("unable to create zip file '%s': "
Andrew M. Kuchlingcdd21572002-11-21 18:33:28 +000088 "could neither import the 'zipfile' module nor "
Collin Winter5b7e9d72007-08-30 03:52:21 +000089 "find a standalone zip utility") % zip_filename)
Andrew M. Kuchlingcdd21572002-11-21 18:33:28 +000090
91 else:
92 log.info("creating '%s' and adding '%s' to it",
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +000093 zip_filename, base_dir)
Andrew M. Kuchlingcdd21572002-11-21 18:33:28 +000094
Greg Wardaebf7062000-04-04 02:05:59 +000095 if not dry_run:
Guido van Rossumb61914d2001-04-14 16:17:00 +000096 z = zipfile.ZipFile(zip_filename, "w",
Greg Wardca4289f2000-09-26 02:13:49 +000097 compression=zipfile.ZIP_DEFLATED)
Greg Wardaebf7062000-04-04 02:05:59 +000098
Benjamin Peterson699adb92008-05-08 22:27:58 +000099 for dirpath, dirnames, filenames in os.walk(base_dir):
100 for name in filenames:
101 path = os.path.normpath(os.path.join(dirpath, name))
102 if os.path.isfile(path):
103 z.write(path, path)
104 log.info("adding '%s'" % path)
Greg Wardaebf7062000-04-04 02:05:59 +0000105 z.close()
106
107 return zip_filename
108
109# make_zipfile ()
110
111
Greg Warddb807542000-04-22 03:09:56 +0000112ARCHIVE_FORMATS = {
Greg Ward2ff78872000-06-24 00:23:20 +0000113 'gztar': (make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"),
114 'bztar': (make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"),
115 'ztar': (make_tarball, [('compress', 'compress')], "compressed tar file"),
116 'tar': (make_tarball, [('compress', None)], "uncompressed tar file"),
Greg Ward04e25a12000-08-22 01:48:54 +0000117 'zip': (make_zipfile, [],"ZIP file")
Greg Warddb807542000-04-22 03:09:56 +0000118 }
119
120def check_archive_formats (formats):
121 for format in formats:
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000122 if format not in ARCHIVE_FORMATS:
Greg Warddb807542000-04-22 03:09:56 +0000123 return format
124 else:
125 return None
126
Greg Wardaebf7062000-04-04 02:05:59 +0000127def make_archive (base_name, format,
128 root_dir=None, base_dir=None,
129 verbose=0, dry_run=0):
Greg Wardaebf7062000-04-04 02:05:59 +0000130 """Create an archive file (eg. zip or tar). 'base_name' is the name
131 of the file to create, minus any format-specific extension; 'format'
132 is the archive format: one of "zip", "tar", "ztar", or "gztar".
133 'root_dir' is a directory that will be the root directory of the
134 archive; ie. we typically chdir into 'root_dir' before creating the
135 archive. 'base_dir' is the directory where we start archiving from;
136 ie. 'base_dir' will be the common prefix of all files and
137 directories in the archive. 'root_dir' and 'base_dir' both default
Greg Ward87909612000-06-01 01:07:55 +0000138 to the current directory. Returns the name of the archive file.
139 """
Greg Wardaebf7062000-04-04 02:05:59 +0000140 save_cwd = os.getcwd()
141 if root_dir is not None:
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000142 log.debug("changing into '%s'", root_dir)
Greg Wardca4289f2000-09-26 02:13:49 +0000143 base_name = os.path.abspath(base_name)
Greg Wardaebf7062000-04-04 02:05:59 +0000144 if not dry_run:
Greg Wardca4289f2000-09-26 02:13:49 +0000145 os.chdir(root_dir)
Greg Wardaebf7062000-04-04 02:05:59 +0000146
147 if base_dir is None:
148 base_dir = os.curdir
149
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000150 kwargs = { 'dry_run': dry_run }
Fred Drakeb94b8492001-12-06 20:51:35 +0000151
Greg Warddb807542000-04-22 03:09:56 +0000152 try:
153 format_info = ARCHIVE_FORMATS[format]
154 except KeyError:
Collin Winter5b7e9d72007-08-30 03:52:21 +0000155 raise ValueError("unknown archive format '%s'" % format)
Greg Wardaebf7062000-04-04 02:05:59 +0000156
Greg Warddb807542000-04-22 03:09:56 +0000157 func = format_info[0]
158 for (arg,val) in format_info[1]:
159 kwargs[arg] = val
Neal Norwitzd9108552006-03-17 08:00:19 +0000160 filename = func(base_name, base_dir, **kwargs)
Greg Wardaebf7062000-04-04 02:05:59 +0000161
162 if root_dir is not None:
Jeremy Hyltoncd8a1142002-06-04 20:14:43 +0000163 log.debug("changing back to '%s'", save_cwd)
Greg Wardca4289f2000-09-26 02:13:49 +0000164 os.chdir(save_cwd)
Greg Wardaebf7062000-04-04 02:05:59 +0000165
Greg Ward87909612000-06-01 01:07:55 +0000166 return filename
167
Greg Wardaebf7062000-04-04 02:05:59 +0000168# make_archive ()