Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
dir_util.py239 linesDownload Raw Back to _distutils
1"""distutils.dir_util2 3Utility functions for manipulating directories and directory trees."""4 5import errno6import os7 8from ._log import log9from .errors import DistutilsFileError, DistutilsInternalError10 11# cache for by mkpath() -- in addition to cheapening redundant calls,12# eliminates redundant "creating /foo/bar/baz" messages in dry-run mode13_path_created = {}14 15 16def mkpath(name, mode=0o777, verbose=1, dry_run=0):  # noqa: C90117    """Create a directory and any missing ancestor directories.18 19    If the directory already exists (or if 'name' is the empty string, which20    means the current directory, which of course exists), then do nothing.21    Raise DistutilsFileError if unable to create some directory along the way22    (eg. some sub-path exists, but is a file rather than a directory).23    If 'verbose' is true, print a one-line summary of each mkdir to stdout.24    Return the list of directories actually created.25 26    os.makedirs is not used because:27 28    a) It's new to Python 1.5.2, and29    b) it blows up if the directory already exists (in which case it should30       silently succeed).31    """32 33    global _path_created34 35    # Detect a common bug -- name is None36    if not isinstance(name, str):37        raise DistutilsInternalError(f"mkpath: 'name' must be a string (got {name!r})")38 39    # XXX what's the better way to handle verbosity? print as we create40    # each directory in the path (the current behaviour), or only announce41    # the creation of the whole path? (quite easy to do the latter since42    # we're not using a recursive algorithm)43 44    name = os.path.normpath(name)45    created_dirs = []46    if os.path.isdir(name) or name == '':47        return created_dirs48    if _path_created.get(os.path.abspath(name)):49        return created_dirs50 51    (head, tail) = os.path.split(name)52    tails = [tail]  # stack of lone dirs to create53 54    while head and tail and not os.path.isdir(head):55        (head, tail) = os.path.split(head)56        tails.insert(0, tail)  # push next higher dir onto stack57 58    # now 'head' contains the deepest directory that already exists59    # (that is, the child of 'head' in 'name' is the highest directory60    # that does *not* exist)61    for d in tails:62        # print "head = %s, d = %s: " % (head, d),63        head = os.path.join(head, d)64        abs_head = os.path.abspath(head)65 66        if _path_created.get(abs_head):67            continue68 69        if verbose >= 1:70            log.info("creating %s", head)71 72        if not dry_run:73            try:74                os.mkdir(head, mode)75            except OSError as exc:76                if not (exc.errno == errno.EEXIST and os.path.isdir(head)):77                    raise DistutilsFileError(78                        f"could not create '{head}': {exc.args[-1]}"79                    )80            created_dirs.append(head)81 82        _path_created[abs_head] = 183    return created_dirs84 85 86def create_tree(base_dir, files, mode=0o777, verbose=1, dry_run=0):87    """Create all the empty directories under 'base_dir' needed to put 'files'88    there.89 90    'base_dir' is just the name of a directory which doesn't necessarily91    exist yet; 'files' is a list of filenames to be interpreted relative to92    'base_dir'.  'base_dir' + the directory portion of every file in 'files'93    will be created if it doesn't already exist.  'mode', 'verbose' and94    'dry_run' flags are as for 'mkpath()'.95    """96    # First get the list of directories to create97    need_dir = set(os.path.join(base_dir, os.path.dirname(file)) for file in files)98 99    # Now create them100    for dir in sorted(need_dir):101        mkpath(dir, mode, verbose=verbose, dry_run=dry_run)102 103 104def copy_tree(  # noqa: C901105    src,106    dst,107    preserve_mode=1,108    preserve_times=1,109    preserve_symlinks=0,110    update=0,111    verbose=1,112    dry_run=0,113):114    """Copy an entire directory tree 'src' to a new location 'dst'.115 116    Both 'src' and 'dst' must be directory names.  If 'src' is not a117    directory, raise DistutilsFileError.  If 'dst' does not exist, it is118    created with 'mkpath()'.  The end result of the copy is that every119    file in 'src' is copied to 'dst', and directories under 'src' are120    recursively copied to 'dst'.  Return the list of files that were121    copied or might have been copied, using their output name.  The122    return value is unaffected by 'update' or 'dry_run': it is simply123    the list of all files under 'src', with the names changed to be124    under 'dst'.125 126    'preserve_mode' and 'preserve_times' are the same as for127    'copy_file'; note that they only apply to regular files, not to128    directories.  If 'preserve_symlinks' is true, symlinks will be129    copied as symlinks (on platforms that support them!); otherwise130    (the default), the destination of the symlink will be copied.131    'update' and 'verbose' are the same as for 'copy_file'.132    """133    from distutils.file_util import copy_file134 135    if not dry_run and not os.path.isdir(src):136        raise DistutilsFileError("cannot copy tree '%s': not a directory" % src)137    try:138        names = os.listdir(src)139    except OSError as e:140        if dry_run:141            names = []142        else:143            raise DistutilsFileError(f"error listing files in '{src}': {e.strerror}")144 145    if not dry_run:146        mkpath(dst, verbose=verbose)147 148    outputs = []149 150    for n in names:151        src_name = os.path.join(src, n)152        dst_name = os.path.join(dst, n)153 154        if n.startswith('.nfs'):155            # skip NFS rename files156            continue157 158        if preserve_symlinks and os.path.islink(src_name):159            link_dest = os.readlink(src_name)160            if verbose >= 1:161                log.info("linking %s -> %s", dst_name, link_dest)162            if not dry_run:163                os.symlink(link_dest, dst_name)164            outputs.append(dst_name)165 166        elif os.path.isdir(src_name):167            outputs.extend(168                copy_tree(169                    src_name,170                    dst_name,171                    preserve_mode,172                    preserve_times,173                    preserve_symlinks,174                    update,175                    verbose=verbose,176                    dry_run=dry_run,177                )178            )179        else:180            copy_file(181                src_name,182                dst_name,183                preserve_mode,184                preserve_times,185                update,186                verbose=verbose,187                dry_run=dry_run,188            )189            outputs.append(dst_name)190 191    return outputs192 193 194def _build_cmdtuple(path, cmdtuples):195    """Helper for remove_tree()."""196    for f in os.listdir(path):197        real_f = os.path.join(path, f)198        if os.path.isdir(real_f) and not os.path.islink(real_f):199            _build_cmdtuple(real_f, cmdtuples)200        else:201            cmdtuples.append((os.remove, real_f))202    cmdtuples.append((os.rmdir, path))203 204 205def remove_tree(directory, verbose=1, dry_run=0):206    """Recursively remove an entire directory tree.207 208    Any errors are ignored (apart from being reported to stdout if 'verbose'209    is true).210    """211    global _path_created212 213    if verbose >= 1:214        log.info("removing '%s' (and everything under it)", directory)215    if dry_run:216        return217    cmdtuples = []218    _build_cmdtuple(directory, cmdtuples)219    for cmd in cmdtuples:220        try:221            cmd[0](cmd[1])222            # remove dir from cache if it's already there223            abspath = os.path.abspath(cmd[1])224            if abspath in _path_created:225                _path_created.pop(abspath)226        except OSError as exc:227            log.warning("error removing %s: %s", directory, exc)228 229 230def ensure_relative(path):231    """Take the full path 'path', and make it a relative path.232 233    This is useful to make 'path' the second argument to os.path.join().234    """235    drive, path = os.path.splitdrive(path)236    if path[0:1] == os.sep:237        path = drive + path[1:]238    return path239 
codekingpro/portable-devtools · Team Ai