]> git.saurik.com Git - wxWidgets.git/blame - wxPython/distutils/archive_util.py
added tech note about writing unit tests
[wxWidgets.git] / wxPython / distutils / archive_util.py
CommitLineData
1e4a197e
RD
1"""distutils.archive_util
2
3Utility functions for creating archive files (tarballs, zip files,
4that sort of thing)."""
5
6# This module should be kept compatible with Python 1.5.2.
7
8__revision__ = "$Id$"
9
10import os
11from distutils.errors import DistutilsExecError
12from distutils.spawn import spawn
13from distutils.dir_util import mkpath
14from distutils import log
15
16def make_tarball (base_name, base_dir, compress="gzip",
17 verbose=0, dry_run=0):
18 """Create a (possibly compressed) tar file from all the files under
19 'base_dir'. 'compress' must be "gzip" (the default), "compress",
20 "bzip2", or None. Both "tar" and the compression utility named by
21 'compress' must be on the default program search path, so this is
22 probably Unix-specific. The output tar file will be named 'base_dir' +
23 ".tar", possibly plus the appropriate compression extension (".gz",
24 ".bz2" or ".Z"). Return the output filename.
25 """
26 # XXX GNU tar 1.13 has a nifty option to add a prefix directory.
27 # It's pretty new, though, so we certainly can't require it --
28 # but it would be nice to take advantage of it to skip the
29 # "create a tree of hardlinks" step! (Would also be nice to
30 # detect GNU tar to use its 'z' option and save a step.)
31
32 compress_ext = { 'gzip': ".gz",
33 'bzip2': '.bz2',
34 'compress': ".Z" }
35
36 # flags for compression program, each element of list will be an argument
37 compress_flags = {'gzip': ["-f9"],
38 'compress': ["-f"],
39 'bzip2': ['-f9']}
40
41 if compress is not None and compress not in compress_ext.keys():
42 raise ValueError, \
43 "bad value for 'compress': must be None, 'gzip', or 'compress'"
44
45 archive_name = base_name + ".tar"
46 mkpath(os.path.dirname(archive_name), dry_run=dry_run)
47 cmd = ["tar", "-cf", archive_name, base_dir]
48 spawn(cmd, dry_run=dry_run)
49
50 if compress:
51 spawn([compress] + compress_flags[compress] + [archive_name],
52 dry_run=dry_run)
53 return archive_name + compress_ext[compress]
54 else:
55 return archive_name
56
57# make_tarball ()
58
59
60def make_zipfile (base_name, base_dir, verbose=0, dry_run=0):
61 """Create a zip file from all the files under 'base_dir'. The output
62 zip file will be named 'base_dir' + ".zip". Uses either the "zipfile"
63 Python module (if available) or the InfoZIP "zip" utility (if installed
64 and found on the default search path). If neither tool is available,
65 raises DistutilsExecError. Returns the name of the output zip file.
66 """
67 try:
68 import zipfile
69 except ImportError:
70 zipfile = None
71
72 zip_filename = base_name + ".zip"
73 mkpath(os.path.dirname(zip_filename), dry_run=dry_run)
74
75 # If zipfile module is not available, try spawning an external
76 # 'zip' command.
77 if zipfile is None:
78 if verbose:
79 zipoptions = "-r"
80 else:
81 zipoptions = "-rq"
82
83 try:
84 spawn(["zip", zipoptions, zip_filename, base_dir],
85 dry_run=dry_run)
86 except DistutilsExecError:
87 # XXX really should distinguish between "couldn't find
88 # external 'zip' command" and "zip failed".
89 raise DistutilsExecError, \
90 ("unable to create zip file '%s': "
91 "could neither import the 'zipfile' module nor "
92 "find a standalone zip utility") % zip_filename
93
94 else:
95 log.info("creating '%s' and adding '%s' to it",
96 zip_filename, base_dir)
97
98 def visit (z, dirname, names):
99 for name in names:
100 path = os.path.normpath(os.path.join(dirname, name))
101 if os.path.isfile(path):
102 z.write(path, path)
103 log.info("adding '%s'" % path)
104
105 if not dry_run:
106 z = zipfile.ZipFile(zip_filename, "w",
107 compression=zipfile.ZIP_DEFLATED)
108
109 os.path.walk(base_dir, visit, z)
110 z.close()
111
112 return zip_filename
113
114# make_zipfile ()
115
116
117ARCHIVE_FORMATS = {
118 'gztar': (make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"),
119 'bztar': (make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"),
120 'ztar': (make_tarball, [('compress', 'compress')], "compressed tar file"),
121 'tar': (make_tarball, [('compress', None)], "uncompressed tar file"),
122 'zip': (make_zipfile, [],"ZIP file")
123 }
124
125def check_archive_formats (formats):
126 for format in formats:
127 if not ARCHIVE_FORMATS.has_key(format):
128 return format
129 else:
130 return None
131
132def make_archive (base_name, format,
133 root_dir=None, base_dir=None,
134 verbose=0, dry_run=0):
135 """Create an archive file (eg. zip or tar). 'base_name' is the name
136 of the file to create, minus any format-specific extension; 'format'
137 is the archive format: one of "zip", "tar", "ztar", or "gztar".
138 'root_dir' is a directory that will be the root directory of the
139 archive; ie. we typically chdir into 'root_dir' before creating the
140 archive. 'base_dir' is the directory where we start archiving from;
141 ie. 'base_dir' will be the common prefix of all files and
142 directories in the archive. 'root_dir' and 'base_dir' both default
143 to the current directory. Returns the name of the archive file.
144 """
145 save_cwd = os.getcwd()
146 if root_dir is not None:
147 log.debug("changing into '%s'", root_dir)
148 base_name = os.path.abspath(base_name)
149 if not dry_run:
150 os.chdir(root_dir)
151
152 if base_dir is None:
153 base_dir = os.curdir
154
155 kwargs = { 'dry_run': dry_run }
156
157 try:
158 format_info = ARCHIVE_FORMATS[format]
159 except KeyError:
160 raise ValueError, "unknown archive format '%s'" % format
161
162 func = format_info[0]
163 for (arg,val) in format_info[1]:
164 kwargs[arg] = val
165 filename = apply(func, (base_name, base_dir), kwargs)
166
167 if root_dir is not None:
168 log.debug("changing back to '%s'", save_cwd)
169 os.chdir(save_cwd)
170
171 return filename
172
173# make_archive ()