0001 """distutils.archive_util 0002 0003 Utility functions for creating archive files (tarballs, zip files, 0004 that sort of thing).""" 0005 0006 # This module should be kept compatible with Python 1.5.2. 0007 0008 __revision__ = "$Id: archive_util.py,v 1.16 2004/07/18 06:14:41 tim_one Exp $" 0009 0010 import os 0011 from distutils.errors import DistutilsExecError 0012 from distutils.spawn import spawn 0013 from distutils.dir_util import mkpath 0014 from distutils import log 0015 0016 def make_tarball (base_name, base_dir, compress="gzip", 0017 verbose=0, dry_run=0): 0018 """Create a (possibly compressed) tar file from all the files under 0019 'base_dir'. 'compress' must be "gzip" (the default), "compress", 0020 "bzip2", or None. Both "tar" and the compression utility named by 0021 'compress' must be on the default program search path, so this is 0022 probably Unix-specific. The output tar file will be named 'base_dir' + 0023 ".tar", possibly plus the appropriate compression extension (".gz", 0024 ".bz2" or ".Z"). Return the output filename. 0025 """ 0026 # XXX GNU tar 1.13 has a nifty option to add a prefix directory. 0027 # It's pretty new, though, so we certainly can't require it -- 0028 # but it would be nice to take advantage of it to skip the 0029 # "create a tree of hardlinks" step! (Would also be nice to 0030 # detect GNU tar to use its 'z' option and save a step.) 0031 0032 compress_ext = { 'gzip': ".gz", 0033 'bzip2': '.bz2', 0034 'compress': ".Z" } 0035 0036 # flags for compression program, each element of list will be an argument 0037 compress_flags = {'gzip': ["-f9"], 0038 'compress': ["-f"], 0039 'bzip2': ['-f9']} 0040 0041 if compress is not None and compress not in compress_ext.keys(): 0042 raise ValueError, \ 0043 "bad value for 'compress': must be None, 'gzip', or 'compress'" 0044 0045 archive_name = base_name + ".tar" 0046 mkpath(os.path.dirname(archive_name), dry_run=dry_run) 0047 cmd = ["tar", "-cf", archive_name, base_dir] 0048 spawn(cmd, dry_run=dry_run) 0049 0050 if compress: 0051 spawn([compress] + compress_flags[compress] + [archive_name], 0052 dry_run=dry_run) 0053 return archive_name + compress_ext[compress] 0054 else: 0055 return archive_name 0056 0057 # make_tarball () 0058 0059 0060 def make_zipfile (base_name, base_dir, verbose=0, dry_run=0): 0061 """Create a zip file from all the files under 'base_dir'. The output 0062 zip file will be named 'base_dir' + ".zip". Uses either the "zipfile" 0063 Python module (if available) or the InfoZIP "zip" utility (if installed 0064 and found on the default search path). If neither tool is available, 0065 raises DistutilsExecError. Returns the name of the output zip file. 0066 """ 0067 try: 0068 import zipfile 0069 except ImportError: 0070 zipfile = None 0071 0072 zip_filename = base_name + ".zip" 0073 mkpath(os.path.dirname(zip_filename), dry_run=dry_run) 0074 0075 # If zipfile module is not available, try spawning an external 0076 # 'zip' command. 0077 if zipfile is None: 0078 if verbose: 0079 zipoptions = "-r" 0080 else: 0081 zipoptions = "-rq" 0082 0083 try: 0084 spawn(["zip", zipoptions, zip_filename, base_dir], 0085 dry_run=dry_run) 0086 except DistutilsExecError: 0087 # XXX really should distinguish between "couldn't find 0088 # external 'zip' command" and "zip failed". 0089 raise DistutilsExecError, \ 0090 ("unable to create zip file '%s': " 0091 "could neither import the 'zipfile' module nor " 0092 "find a standalone zip utility") % zip_filename 0093 0094 else: 0095 log.info("creating '%s' and adding '%s' to it", 0096 zip_filename, base_dir) 0097 0098 def visit (z, dirname, names): 0099 for name in names: 0100 path = os.path.normpath(os.path.join(dirname, name)) 0101 if os.path.isfile(path): 0102 z.write(path, path) 0103 log.info("adding '%s'" % path) 0104 0105 if not dry_run: 0106 z = zipfile.ZipFile(zip_filename, "w", 0107 compression=zipfile.ZIP_DEFLATED) 0108 0109 os.path.walk(base_dir, visit, z) 0110 z.close() 0111 0112 return zip_filename 0113 0114 # make_zipfile () 0115 0116 0117 ARCHIVE_FORMATS = { 0118 'gztar': (make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"), 0119 'bztar': (make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"), 0120 'ztar': (make_tarball, [('compress', 'compress')], "compressed tar file"), 0121 'tar': (make_tarball, [('compress', None)], "uncompressed tar file"), 0122 'zip': (make_zipfile, [],"ZIP file") 0123 } 0124 0125 def check_archive_formats (formats): 0126 for format in formats: 0127 if not ARCHIVE_FORMATS.has_key(format): 0128 return format 0129 else: 0130 return None 0131 0132 def make_archive (base_name, format, 0133 root_dir=None, base_dir=None, 0134 verbose=0, dry_run=0): 0135 """Create an archive file (eg. zip or tar). 'base_name' is the name 0136 of the file to create, minus any format-specific extension; 'format' 0137 is the archive format: one of "zip", "tar", "ztar", or "gztar". 0138 'root_dir' is a directory that will be the root directory of the 0139 archive; ie. we typically chdir into 'root_dir' before creating the 0140 archive. 'base_dir' is the directory where we start archiving from; 0141 ie. 'base_dir' will be the common prefix of all files and 0142 directories in the archive. 'root_dir' and 'base_dir' both default 0143 to the current directory. Returns the name of the archive file. 0144 """ 0145 save_cwd = os.getcwd() 0146 if root_dir is not None: 0147 log.debug("changing into '%s'", root_dir) 0148 base_name = os.path.abspath(base_name) 0149 if not dry_run: 0150 os.chdir(root_dir) 0151 0152 if base_dir is None: 0153 base_dir = os.curdir 0154 0155 kwargs = { 'dry_run': dry_run } 0156 0157 try: 0158 format_info = ARCHIVE_FORMATS[format] 0159 except KeyError: 0160 raise ValueError, "unknown archive format '%s'" % format 0161 0162 func = format_info[0] 0163 for (arg,val) in format_info[1]: 0164 kwargs[arg] = val 0165 filename = apply(func, (base_name, base_dir), kwargs) 0166 0167 if root_dir is not None: 0168 log.debug("changing back to '%s'", save_cwd) 0169 os.chdir(save_cwd) 0170 0171 return filename 0172 0173 # make_archive () 0174
Generated by PyXR 0.9.4