]>
jfr.im git - dlqueue.git/blob - venv/lib/python3.11/site-packages/setuptools/_distutils/dir_util.py
3 Utility functions for manipulating directories and directory trees."""
7 from .errors
import DistutilsInternalError
, DistutilsFileError
10 # cache for by mkpath() -- in addition to cheapening redundant calls,
11 # eliminates redundant "creating /foo/bar/baz" messages in dry-run mode
15 def mkpath(name
, mode
=0o777, verbose
=1, dry_run
=0): # noqa: C901
16 """Create a directory and any missing ancestor directories.
18 If the directory already exists (or if 'name' is the empty string, which
19 means the current directory, which of course exists), then do nothing.
20 Raise DistutilsFileError if unable to create some directory along the way
21 (eg. some sub-path exists, but is a file rather than a directory).
22 If 'verbose' is true, print a one-line summary of each mkdir to stdout.
23 Return the list of directories actually created.
25 os.makedirs is not used because:
27 a) It's new to Python 1.5.2, and
28 b) it blows up if the directory already exists (in which case it should
34 # Detect a common bug -- name is None
35 if not isinstance(name
, str):
36 raise DistutilsInternalError(
37 "mkpath: 'name' must be a string (got {!r})".format(name
)
40 # XXX what's the better way to handle verbosity? print as we create
41 # each directory in the path (the current behaviour), or only announce
42 # the creation of the whole path? (quite easy to do the latter since
43 # we're not using a recursive algorithm)
45 name
= os
.path
.normpath(name
)
47 if os
.path
.isdir(name
) or name
== '':
49 if _path_created
.get(os
.path
.abspath(name
)):
52 (head
, tail
) = os
.path
.split(name
)
53 tails
= [tail
] # stack of lone dirs to create
55 while head
and tail
and not os
.path
.isdir(head
):
56 (head
, tail
) = os
.path
.split(head
)
57 tails
.insert(0, tail
) # push next higher dir onto stack
59 # now 'head' contains the deepest directory that already exists
60 # (that is, the child of 'head' in 'name' is the highest directory
61 # that does *not* exist)
63 # print "head = %s, d = %s: " % (head, d),
64 head
= os
.path
.join(head
, d
)
65 abs_head
= os
.path
.abspath(head
)
67 if _path_created
.get(abs_head
):
71 log
.info("creating %s", head
)
76 except OSError as exc
:
77 if not (exc
.errno
== errno
.EEXIST
and os
.path
.isdir(head
)):
78 raise DistutilsFileError(
79 "could not create '{}': {}".format(head
, exc
.args
[-1])
81 created_dirs
.append(head
)
83 _path_created
[abs_head
] = 1
87 def create_tree(base_dir
, files
, mode
=0o777, verbose
=1, dry_run
=0):
88 """Create all the empty directories under 'base_dir' needed to put 'files'
91 'base_dir' is just the name of a directory which doesn't necessarily
92 exist yet; 'files' is a list of filenames to be interpreted relative to
93 'base_dir'. 'base_dir' + the directory portion of every file in 'files'
94 will be created if it doesn't already exist. 'mode', 'verbose' and
95 'dry_run' flags are as for 'mkpath()'.
97 # First get the list of directories to create
100 need_dir
.add(os
.path
.join(base_dir
, os
.path
.dirname(file)))
103 for dir in sorted(need_dir
):
104 mkpath(dir, mode
, verbose
=verbose
, dry_run
=dry_run
)
107 def copy_tree( # noqa: C901
117 """Copy an entire directory tree 'src' to a new location 'dst'.
119 Both 'src' and 'dst' must be directory names. If 'src' is not a
120 directory, raise DistutilsFileError. If 'dst' does not exist, it is
121 created with 'mkpath()'. The end result of the copy is that every
122 file in 'src' is copied to 'dst', and directories under 'src' are
123 recursively copied to 'dst'. Return the list of files that were
124 copied or might have been copied, using their output name. The
125 return value is unaffected by 'update' or 'dry_run': it is simply
126 the list of all files under 'src', with the names changed to be
129 'preserve_mode' and 'preserve_times' are the same as for
130 'copy_file'; note that they only apply to regular files, not to
131 directories. If 'preserve_symlinks' is true, symlinks will be
132 copied as symlinks (on platforms that support them!); otherwise
133 (the default), the destination of the symlink will be copied.
134 'update' and 'verbose' are the same as for 'copy_file'.
136 from distutils
.file_util
import copy_file
138 if not dry_run
and not os
.path
.isdir(src
):
139 raise DistutilsFileError("cannot copy tree '%s': not a directory" % src
)
141 names
= os
.listdir(src
)
146 raise DistutilsFileError(
147 "error listing files in '{}': {}".format(src
, e
.strerror
)
151 mkpath(dst
, verbose
=verbose
)
156 src_name
= os
.path
.join(src
, n
)
157 dst_name
= os
.path
.join(dst
, n
)
159 if n
.startswith('.nfs'):
160 # skip NFS rename files
163 if preserve_symlinks
and os
.path
.islink(src_name
):
164 link_dest
= os
.readlink(src_name
)
166 log
.info("linking %s -> %s", dst_name
, link_dest
)
168 os
.symlink(link_dest
, dst_name
)
169 outputs
.append(dst_name
)
171 elif os
.path
.isdir(src_name
):
194 outputs
.append(dst_name
)
199 def _build_cmdtuple(path
, cmdtuples
):
200 """Helper for remove_tree()."""
201 for f
in os
.listdir(path
):
202 real_f
= os
.path
.join(path
, f
)
203 if os
.path
.isdir(real_f
) and not os
.path
.islink(real_f
):
204 _build_cmdtuple(real_f
, cmdtuples
)
206 cmdtuples
.append((os
.remove
, real_f
))
207 cmdtuples
.append((os
.rmdir
, path
))
210 def remove_tree(directory
, verbose
=1, dry_run
=0):
211 """Recursively remove an entire directory tree.
213 Any errors are ignored (apart from being reported to stdout if 'verbose'
219 log
.info("removing '%s' (and everything under it)", directory
)
223 _build_cmdtuple(directory
, cmdtuples
)
224 for cmd
in cmdtuples
:
227 # remove dir from cache if it's already there
228 abspath
= os
.path
.abspath(cmd
[1])
229 if abspath
in _path_created
:
230 _path_created
.pop(abspath
)
231 except OSError as exc
:
232 log
.warning("error removing %s: %s", directory
, exc
)
235 def ensure_relative(path
):
236 """Take the full path 'path', and make it a relative path.
238 This is useful to make 'path' the second argument to os.path.join().
240 drive
, path
= os
.path
.splitdrive(path
)
241 if path
[0:1] == os
.sep
:
242 path
= drive
+ path
[1:]