Ignore:
Timestamp:
Mar 19, 2014, 11:11:30 AM (11 years ago)
Author:
dmik
Message:

python: Update vendor to 2.7.6.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • python/vendor/current/Lib/shutil.py

    r2 r388  
    1 """Utility functions for copying files and directory trees.
     1"""Utility functions for copying and archiving files and directory trees.
    22
    33XXX The functions here don't copy the resource fork or other metadata on Mac.
     
    1010from os.path import abspath
    1111import fnmatch
    12 
    13 __all__ = ["copyfileobj","copyfile","copymode","copystat","copy","copy2",
    14            "copytree","move","rmtree","Error"]
     12import collections
     13import errno
     14
     15try:
     16    from pwd import getpwnam
     17except ImportError:
     18    getpwnam = None
     19
     20try:
     21    from grp import getgrnam
     22except ImportError:
     23    getgrnam = None
     24
     25__all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2",
     26           "copytree", "move", "rmtree", "Error", "SpecialFileError",
     27           "ExecError", "make_archive", "get_archive_formats",
     28           "register_archive_format", "unregister_archive_format",
     29           "ignore_patterns"]
    1530
    1631class Error(EnvironmentError):
    1732    pass
     33
     34class SpecialFileError(EnvironmentError):
     35    """Raised when trying to do a kind of operation (e.g. copying) which is
     36    not supported on a special file (e.g. a named pipe)"""
     37
     38class ExecError(EnvironmentError):
     39    """Raised when a command could not be executed"""
    1840
    1941try:
     
    3254def _samefile(src, dst):
    3355    # Macintosh, Unix.
    34     if hasattr(os.path,'samefile'):
     56    if hasattr(os.path, 'samefile'):
    3557        try:
    3658            return os.path.samefile(src, dst)
     
    4567    """Copy data from src to dst"""
    4668    if _samefile(src, dst):
    47         raise Error, "`%s` and `%s` are the same file" % (src, dst)
    48 
    49     fsrc = None
    50     fdst = None
    51     try:
    52         fsrc = open(src, 'rb')
    53         fdst = open(dst, 'wb')
    54         copyfileobj(fsrc, fdst)
    55     finally:
    56         if fdst:
    57             fdst.close()
    58         if fsrc:
    59             fsrc.close()
     69        raise Error("`%s` and `%s` are the same file" % (src, dst))
     70
     71    for fn in [src, dst]:
     72        try:
     73            st = os.stat(fn)
     74        except OSError:
     75            # File most likely does not exist
     76            pass
     77        else:
     78            # XXX What about other special files? (sockets, devices...)
     79            if stat.S_ISFIFO(st.st_mode):
     80                raise SpecialFileError("`%s` is a named pipe" % fn)
     81
     82    with open(src, 'rb') as fsrc:
     83        with open(dst, 'wb') as fdst:
     84            copyfileobj(fsrc, fdst)
    6085
    6186def copymode(src, dst):
     
    75100        os.chmod(dst, mode)
    76101    if hasattr(os, 'chflags') and hasattr(st, 'st_flags'):
    77         os.chflags(dst, st.st_flags)
    78 
     102        try:
     103            os.chflags(dst, st.st_flags)
     104        except OSError, why:
     105            for err in 'EOPNOTSUPP', 'ENOTSUP':
     106                if hasattr(errno, err) and why.errno == getattr(errno, err):
     107                    break
     108            else:
     109                raise
    79110
    80111def copy(src, dst):
     
    158189                copytree(srcname, dstname, symlinks, ignore)
    159190            else:
     191                # Will raise a SpecialFileError for unsupported file types
    160192                copy2(srcname, dstname)
    161             # XXX What about devices, sockets etc.?
    162         except (IOError, os.error), why:
    163             errors.append((srcname, dstname, str(why)))
    164193        # catch the Error from the recursive copytree so that we can
    165194        # continue with other files
    166195        except Error, err:
    167196            errors.extend(err.args[0])
     197        except EnvironmentError, why:
     198            errors.append((srcname, dstname, str(why)))
    168199    try:
    169200        copystat(src, dst)
     
    173204            pass
    174205        else:
    175             errors.extend((src, dst, str(why)))
     206            errors.append((src, dst, str(why)))
    176207    if errors:
    177208        raise Error, errors
     
    250281    real_dst = dst
    251282    if os.path.isdir(dst):
     283        if _samefile(src, dst):
     284            # We might be on a case insensitive filesystem,
     285            # perform the rename anyway.
     286            os.rename(src, dst)
     287            return
     288
    252289        real_dst = os.path.join(dst, _basename(src))
    253290        if os.path.exists(real_dst):
     
    257294    except OSError:
    258295        if os.path.isdir(src):
    259             if destinsrc(src, dst):
     296            if _destinsrc(src, dst):
    260297                raise Error, "Cannot move a directory '%s' into itself '%s'." % (src, dst)
    261298            copytree(src, real_dst, symlinks=True)
     
    265302            os.unlink(src)
    266303
    267 def destinsrc(src, dst):
     304def _destinsrc(src, dst):
    268305    src = abspath(src)
    269306    dst = abspath(dst)
     
    273310        dst += os.path.sep
    274311    return dst.startswith(src)
     312
     313def _get_gid(name):
     314    """Returns a gid, given a group name."""
     315    if getgrnam is None or name is None:
     316        return None
     317    try:
     318        result = getgrnam(name)
     319    except KeyError:
     320        result = None
     321    if result is not None:
     322        return result[2]
     323    return None
     324
     325def _get_uid(name):
     326    """Returns an uid, given a user name."""
     327    if getpwnam is None or name is None:
     328        return None
     329    try:
     330        result = getpwnam(name)
     331    except KeyError:
     332        result = None
     333    if result is not None:
     334        return result[2]
     335    return None
     336
     337def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
     338                  owner=None, group=None, logger=None):
     339    """Create a (possibly compressed) tar file from all the files under
     340    'base_dir'.
     341
     342    'compress' must be "gzip" (the default), "bzip2", or None.
     343
     344    'owner' and 'group' can be used to define an owner and a group for the
     345    archive that is being built. If not provided, the current owner and group
     346    will be used.
     347
     348    The output tar file will be named 'base_name' +  ".tar", possibly plus
     349    the appropriate compression extension (".gz", or ".bz2").
     350
     351    Returns the output filename.
     352    """
     353    tar_compression = {'gzip': 'gz', 'bzip2': 'bz2', None: ''}
     354    compress_ext = {'gzip': '.gz', 'bzip2': '.bz2'}
     355
     356    # flags for compression program, each element of list will be an argument
     357    if compress is not None and compress not in compress_ext.keys():
     358        raise ValueError, \
     359              ("bad value for 'compress': must be None, 'gzip' or 'bzip2'")
     360
     361    archive_name = base_name + '.tar' + compress_ext.get(compress, '')
     362    archive_dir = os.path.dirname(archive_name)
     363
     364    if not os.path.exists(archive_dir):
     365        if logger is not None:
     366            logger.info("creating %s", archive_dir)
     367        if not dry_run:
     368            os.makedirs(archive_dir)
     369
     370
     371    # creating the tarball
     372    import tarfile  # late import so Python build itself doesn't break
     373
     374    if logger is not None:
     375        logger.info('Creating tar archive')
     376
     377    uid = _get_uid(owner)
     378    gid = _get_gid(group)
     379
     380    def _set_uid_gid(tarinfo):
     381        if gid is not None:
     382            tarinfo.gid = gid
     383            tarinfo.gname = group
     384        if uid is not None:
     385            tarinfo.uid = uid
     386            tarinfo.uname = owner
     387        return tarinfo
     388
     389    if not dry_run:
     390        tar = tarfile.open(archive_name, 'w|%s' % tar_compression[compress])
     391        try:
     392            tar.add(base_dir, filter=_set_uid_gid)
     393        finally:
     394            tar.close()
     395
     396    return archive_name
     397
     398def _call_external_zip(base_dir, zip_filename, verbose=False, dry_run=False):
     399    # XXX see if we want to keep an external call here
     400    if verbose:
     401        zipoptions = "-r"
     402    else:
     403        zipoptions = "-rq"
     404    from distutils.errors import DistutilsExecError
     405    from distutils.spawn import spawn
     406    try:
     407        spawn(["zip", zipoptions, zip_filename, base_dir], dry_run=dry_run)
     408    except DistutilsExecError:
     409        # XXX really should distinguish between "couldn't find
     410        # external 'zip' command" and "zip failed".
     411        raise ExecError, \
     412            ("unable to create zip file '%s': "
     413            "could neither import the 'zipfile' module nor "
     414            "find a standalone zip utility") % zip_filename
     415
     416def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None):
     417    """Create a zip file from all the files under 'base_dir'.
     418
     419    The output zip file will be named 'base_name' + ".zip".  Uses either the
     420    "zipfile" Python module (if available) or the InfoZIP "zip" utility
     421    (if installed and found on the default search path).  If neither tool is
     422    available, raises ExecError.  Returns the name of the output zip
     423    file.
     424    """
     425    zip_filename = base_name + ".zip"
     426    archive_dir = os.path.dirname(base_name)
     427
     428    if not os.path.exists(archive_dir):
     429        if logger is not None:
     430            logger.info("creating %s", archive_dir)
     431        if not dry_run:
     432            os.makedirs(archive_dir)
     433
     434    # If zipfile module is not available, try spawning an external 'zip'
     435    # command.
     436    try:
     437        import zipfile
     438    except ImportError:
     439        zipfile = None
     440
     441    if zipfile is None:
     442        _call_external_zip(base_dir, zip_filename, verbose, dry_run)
     443    else:
     444        if logger is not None:
     445            logger.info("creating '%s' and adding '%s' to it",
     446                        zip_filename, base_dir)
     447
     448        if not dry_run:
     449            zip = zipfile.ZipFile(zip_filename, "w",
     450                                  compression=zipfile.ZIP_DEFLATED)
     451
     452            for dirpath, dirnames, filenames in os.walk(base_dir):
     453                for name in filenames:
     454                    path = os.path.normpath(os.path.join(dirpath, name))
     455                    if os.path.isfile(path):
     456                        zip.write(path, path)
     457                        if logger is not None:
     458                            logger.info("adding '%s'", path)
     459            zip.close()
     460
     461    return zip_filename
     462
     463_ARCHIVE_FORMATS = {
     464    'gztar': (_make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"),
     465    'bztar': (_make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"),
     466    'tar':   (_make_tarball, [('compress', None)], "uncompressed tar file"),
     467    'zip':   (_make_zipfile, [],"ZIP file")
     468    }
     469
     470def get_archive_formats():
     471    """Returns a list of supported formats for archiving and unarchiving.
     472
     473    Each element of the returned sequence is a tuple (name, description)
     474    """
     475    formats = [(name, registry[2]) for name, registry in
     476               _ARCHIVE_FORMATS.items()]
     477    formats.sort()
     478    return formats
     479
     480def register_archive_format(name, function, extra_args=None, description=''):
     481    """Registers an archive format.
     482
     483    name is the name of the format. function is the callable that will be
     484    used to create archives. If provided, extra_args is a sequence of
     485    (name, value) tuples that will be passed as arguments to the callable.
     486    description can be provided to describe the format, and will be returned
     487    by the get_archive_formats() function.
     488    """
     489    if extra_args is None:
     490        extra_args = []
     491    if not isinstance(function, collections.Callable):
     492        raise TypeError('The %s object is not callable' % function)
     493    if not isinstance(extra_args, (tuple, list)):
     494        raise TypeError('extra_args needs to be a sequence')
     495    for element in extra_args:
     496        if not isinstance(element, (tuple, list)) or len(element) !=2 :
     497            raise TypeError('extra_args elements are : (arg_name, value)')
     498
     499    _ARCHIVE_FORMATS[name] = (function, extra_args, description)
     500
     501def unregister_archive_format(name):
     502    del _ARCHIVE_FORMATS[name]
     503
     504def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
     505                 dry_run=0, owner=None, group=None, logger=None):
     506    """Create an archive file (eg. zip or tar).
     507
     508    'base_name' is the name of the file to create, minus any format-specific
     509    extension; 'format' is the archive format: one of "zip", "tar", "bztar"
     510    or "gztar".
     511
     512    'root_dir' is a directory that will be the root directory of the
     513    archive; ie. we typically chdir into 'root_dir' before creating the
     514    archive.  'base_dir' is the directory where we start archiving from;
     515    ie. 'base_dir' will be the common prefix of all files and
     516    directories in the archive.  'root_dir' and 'base_dir' both default
     517    to the current directory.  Returns the name of the archive file.
     518
     519    'owner' and 'group' are used when creating a tar archive. By default,
     520    uses the current owner and group.
     521    """
     522    save_cwd = os.getcwd()
     523    if root_dir is not None:
     524        if logger is not None:
     525            logger.debug("changing into '%s'", root_dir)
     526        base_name = os.path.abspath(base_name)
     527        if not dry_run:
     528            os.chdir(root_dir)
     529
     530    if base_dir is None:
     531        base_dir = os.curdir
     532
     533    kwargs = {'dry_run': dry_run, 'logger': logger}
     534
     535    try:
     536        format_info = _ARCHIVE_FORMATS[format]
     537    except KeyError:
     538        raise ValueError, "unknown archive format '%s'" % format
     539
     540    func = format_info[0]
     541    for arg, val in format_info[1]:
     542        kwargs[arg] = val
     543
     544    if format != 'zip':
     545        kwargs['owner'] = owner
     546        kwargs['group'] = group
     547
     548    try:
     549        filename = func(base_name, base_dir, **kwargs)
     550    finally:
     551        if root_dir is not None:
     552            if logger is not None:
     553                logger.debug("changing back to '%s'", save_cwd)
     554            os.chdir(save_cwd)
     555
     556    return filename
Note: See TracChangeset for help on using the changeset viewer.