diff options
Diffstat (limited to 'Lib/shutil.py')
-rw-r--r-- | Lib/shutil.py | 102 |
1 files changed, 51 insertions, 51 deletions
diff --git a/Lib/shutil.py b/Lib/shutil.py index ac06ae5..61dc804 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -7,7 +7,6 @@ XXX The functions here don't copy the resource fork or other metadata on Mac. import os import sys import stat -from os.path import abspath import fnmatch import collections import errno @@ -21,6 +20,13 @@ except ImportError: _BZ2_SUPPORTED = False try: + import lzma + del lzma + _LZMA_SUPPORTED = True +except ImportError: + _LZMA_SUPPORTED = False + +try: from pwd import getpwnam except ImportError: getpwnam = None @@ -487,7 +493,7 @@ def _basename(path): sep = os.path.sep + (os.path.altsep or '') return os.path.basename(path.rstrip(sep)) -def move(src, dst): +def move(src, dst, copy_function=copy2): """Recursively move a file or directory to another location. This is similar to the Unix "mv" command. Return the file or directory's destination. @@ -504,6 +510,11 @@ def move(src, dst): recreated under the new name if os.rename() fails because of cross filesystem renames. + The optional `copy_function` argument is a callable that will be used + to copy the source or it will be delegated to `copytree`. + By default, copy2() is used, but any function that supports the same + signature (like copy()) can be used. + A lot more could be done here... A look at a mv.c shows a lot of the issues this implementation glosses over. @@ -528,17 +539,19 @@ def move(src, dst): os.unlink(src) elif os.path.isdir(src): if _destinsrc(src, dst): - raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst)) - copytree(src, real_dst, symlinks=True) + raise Error("Cannot move a directory '%s' into itself" + " '%s'." % (src, dst)) + copytree(src, real_dst, copy_function=copy_function, + symlinks=True) rmtree(src) else: - copy2(src, real_dst) + copy_function(src, real_dst) os.unlink(src) return real_dst def _destinsrc(src, dst): - src = abspath(src) - dst = abspath(dst) + src = os.path.abspath(src) + dst = os.path.abspath(dst) if not src.endswith(os.path.sep): src += os.path.sep if not dst.endswith(os.path.sep): @@ -574,14 +587,14 @@ def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0, """Create a (possibly compressed) tar file from all the files under 'base_dir'. - 'compress' must be "gzip" (the default), "bzip2", or None. + 'compress' must be "gzip" (the default), "bzip2", "xz", or None. 'owner' and 'group' can be used to define an owner and a group for the archive that is being built. If not provided, the current owner and group will be used. The output tar file will be named 'base_name' + ".tar", possibly plus - the appropriate compression extension (".gz", or ".bz2"). + the appropriate compression extension (".gz", ".bz2", or ".xz"). Returns the output filename. """ @@ -592,6 +605,10 @@ def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0, tar_compression['bzip2'] = 'bz2' compress_ext['bzip2'] = '.bz2' + if _LZMA_SUPPORTED: + tar_compression['xz'] = 'xz' + compress_ext['xz'] = '.xz' + # flags for compression program, each element of list will be an argument if compress is not None and compress not in compress_ext: raise ValueError("bad value for 'compress', or compression format not " @@ -631,23 +648,6 @@ def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0, return archive_name -def _call_external_zip(base_dir, zip_filename, verbose=False, dry_run=False): - # XXX see if we want to keep an external call here - if verbose: - zipoptions = "-r" - else: - zipoptions = "-rq" - from distutils.errors import DistutilsExecError - from distutils.spawn import spawn - try: - spawn(["zip", zipoptions, zip_filename, base_dir], dry_run=dry_run) - except DistutilsExecError: - # XXX really should distinguish between "couldn't find - # external 'zip' command" and "zip failed". - raise ExecError("unable to create zip file '%s': " - "could neither import the 'zipfile' module nor " - "find a standalone zip utility") % zip_filename - def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None): """Create a zip file from all the files under 'base_dir'. @@ -657,6 +657,8 @@ def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None): available, raises ExecError. Returns the name of the output zip file. """ + import zipfile + zip_filename = base_name + ".zip" archive_dir = os.path.dirname(base_name) @@ -666,30 +668,20 @@ def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None): if not dry_run: os.makedirs(archive_dir) - # If zipfile module is not available, try spawning an external 'zip' - # command. - try: - import zipfile - except ImportError: - zipfile = None - - if zipfile is None: - _call_external_zip(base_dir, zip_filename, verbose, dry_run) - else: - if logger is not None: - logger.info("creating '%s' and adding '%s' to it", - zip_filename, base_dir) + if logger is not None: + logger.info("creating '%s' and adding '%s' to it", + zip_filename, base_dir) - if not dry_run: - with zipfile.ZipFile(zip_filename, "w", - compression=zipfile.ZIP_DEFLATED) as zf: - for dirpath, dirnames, filenames in os.walk(base_dir): - for name in filenames: - path = os.path.normpath(os.path.join(dirpath, name)) - if os.path.isfile(path): - zf.write(path, path) - if logger is not None: - logger.info("adding '%s'", path) + if not dry_run: + with zipfile.ZipFile(zip_filename, "w", + compression=zipfile.ZIP_DEFLATED) as zf: + for dirpath, dirnames, filenames in os.walk(base_dir): + for name in filenames: + path = os.path.normpath(os.path.join(dirpath, name)) + if os.path.isfile(path): + zf.write(path, path) + if logger is not None: + logger.info("adding '%s'", path) return zip_filename @@ -703,6 +695,10 @@ if _BZ2_SUPPORTED: _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file") +if _LZMA_SUPPORTED: + _ARCHIVE_FORMATS['xztar'] = (_make_tarball, [('compress', 'xz')], + "xz'ed tar-file") + def get_archive_formats(): """Returns a list of supported formats for archiving and unarchiving. @@ -891,7 +887,7 @@ def _unpack_zipfile(filename, extract_dir): zip.close() def _unpack_tarfile(filename, extract_dir): - """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir` + """Unpack tar/tar.gz/tar.bz2/tar.xz `filename` to `extract_dir` """ try: tarobj = tarfile.open(filename) @@ -910,9 +906,13 @@ _UNPACK_FORMATS = { } if _BZ2_SUPPORTED: - _UNPACK_FORMATS['bztar'] = (['.bz2'], _unpack_tarfile, [], + _UNPACK_FORMATS['bztar'] = (['.tar.bz2', '.tbz2'], _unpack_tarfile, [], "bzip2'ed tar-file") +if _LZMA_SUPPORTED: + _UNPACK_FORMATS['xztar'] = (['.tar.xz', '.txz'], _unpack_tarfile, [], + "xz'ed tar-file") + def _find_unpack_format(filename): for name, info in _UNPACK_FORMATS.items(): for extension in info[0]: |