ยปCore Development>Code coverage>Lib/distutils/dir_util.py

Python code coverage for Lib/distutils/dir_util.py

#countcontent
1n/a"""distutils.dir_util
2n/a
3n/aUtility functions for manipulating directories and directory trees."""
4n/a
5n/aimport os
6n/aimport errno
7n/afrom distutils.errors import DistutilsFileError, DistutilsInternalError
8n/afrom distutils import log
9n/a
10n/a# cache for by mkpath() -- in addition to cheapening redundant calls,
11n/a# eliminates redundant "creating /foo/bar/baz" messages in dry-run mode
12n/a_path_created = {}
13n/a
14n/a# I don't use os.makedirs because a) it's new to Python 1.5.2, and
15n/a# b) it blows up if the directory already exists (I want to silently
16n/a# succeed in that case).
17n/adef mkpath(name, mode=0o777, verbose=1, dry_run=0):
18n/a """Create a directory and any missing ancestor directories.
19n/a
20n/a If the directory already exists (or if 'name' is the empty string, which
21n/a means the current directory, which of course exists), then do nothing.
22n/a Raise DistutilsFileError if unable to create some directory along the way
23n/a (eg. some sub-path exists, but is a file rather than a directory).
24n/a If 'verbose' is true, print a one-line summary of each mkdir to stdout.
25n/a Return the list of directories actually created.
26n/a """
27n/a
28n/a global _path_created
29n/a
30n/a # Detect a common bug -- name is None
31n/a if not isinstance(name, str):
32n/a raise DistutilsInternalError(
33n/a "mkpath: 'name' must be a string (got %r)" % (name,))
34n/a
35n/a # XXX what's the better way to handle verbosity? print as we create
36n/a # each directory in the path (the current behaviour), or only announce
37n/a # the creation of the whole path? (quite easy to do the latter since
38n/a # we're not using a recursive algorithm)
39n/a
40n/a name = os.path.normpath(name)
41n/a created_dirs = []
42n/a if os.path.isdir(name) or name == '':
43n/a return created_dirs
44n/a if _path_created.get(os.path.abspath(name)):
45n/a return created_dirs
46n/a
47n/a (head, tail) = os.path.split(name)
48n/a tails = [tail] # stack of lone dirs to create
49n/a
50n/a while head and tail and not os.path.isdir(head):
51n/a (head, tail) = os.path.split(head)
52n/a tails.insert(0, tail) # push next higher dir onto stack
53n/a
54n/a # now 'head' contains the deepest directory that already exists
55n/a # (that is, the child of 'head' in 'name' is the highest directory
56n/a # that does *not* exist)
57n/a for d in tails:
58n/a #print "head = %s, d = %s: " % (head, d),
59n/a head = os.path.join(head, d)
60n/a abs_head = os.path.abspath(head)
61n/a
62n/a if _path_created.get(abs_head):
63n/a continue
64n/a
65n/a if verbose >= 1:
66n/a log.info("creating %s", head)
67n/a
68n/a if not dry_run:
69n/a try:
70n/a os.mkdir(head, mode)
71n/a except OSError as exc:
72n/a if not (exc.errno == errno.EEXIST and os.path.isdir(head)):
73n/a raise DistutilsFileError(
74n/a "could not create '%s': %s" % (head, exc.args[-1]))
75n/a created_dirs.append(head)
76n/a
77n/a _path_created[abs_head] = 1
78n/a return created_dirs
79n/a
80n/adef create_tree(base_dir, files, mode=0o777, verbose=1, dry_run=0):
81n/a """Create all the empty directories under 'base_dir' needed to put 'files'
82n/a there.
83n/a
84n/a 'base_dir' is just the name of a directory which doesn't necessarily
85n/a exist yet; 'files' is a list of filenames to be interpreted relative to
86n/a 'base_dir'. 'base_dir' + the directory portion of every file in 'files'
87n/a will be created if it doesn't already exist. 'mode', 'verbose' and
88n/a 'dry_run' flags are as for 'mkpath()'.
89n/a """
90n/a # First get the list of directories to create
91n/a need_dir = set()
92n/a for file in files:
93n/a need_dir.add(os.path.join(base_dir, os.path.dirname(file)))
94n/a
95n/a # Now create them
96n/a for dir in sorted(need_dir):
97n/a mkpath(dir, mode, verbose=verbose, dry_run=dry_run)
98n/a
99n/adef copy_tree(src, dst, preserve_mode=1, preserve_times=1,
100n/a preserve_symlinks=0, update=0, verbose=1, dry_run=0):
101n/a """Copy an entire directory tree 'src' to a new location 'dst'.
102n/a
103n/a Both 'src' and 'dst' must be directory names. If 'src' is not a
104n/a directory, raise DistutilsFileError. If 'dst' does not exist, it is
105n/a created with 'mkpath()'. The end result of the copy is that every
106n/a file in 'src' is copied to 'dst', and directories under 'src' are
107n/a recursively copied to 'dst'. Return the list of files that were
108n/a copied or might have been copied, using their output name. The
109n/a return value is unaffected by 'update' or 'dry_run': it is simply
110n/a the list of all files under 'src', with the names changed to be
111n/a under 'dst'.
112n/a
113n/a 'preserve_mode' and 'preserve_times' are the same as for
114n/a 'copy_file'; note that they only apply to regular files, not to
115n/a directories. If 'preserve_symlinks' is true, symlinks will be
116n/a copied as symlinks (on platforms that support them!); otherwise
117n/a (the default), the destination of the symlink will be copied.
118n/a 'update' and 'verbose' are the same as for 'copy_file'.
119n/a """
120n/a from distutils.file_util import copy_file
121n/a
122n/a if not dry_run and not os.path.isdir(src):
123n/a raise DistutilsFileError(
124n/a "cannot copy tree '%s': not a directory" % src)
125n/a try:
126n/a names = os.listdir(src)
127n/a except OSError as e:
128n/a if dry_run:
129n/a names = []
130n/a else:
131n/a raise DistutilsFileError(
132n/a "error listing files in '%s': %s" % (src, e.strerror))
133n/a
134n/a if not dry_run:
135n/a mkpath(dst, verbose=verbose)
136n/a
137n/a outputs = []
138n/a
139n/a for n in names:
140n/a src_name = os.path.join(src, n)
141n/a dst_name = os.path.join(dst, n)
142n/a
143n/a if n.startswith('.nfs'):
144n/a # skip NFS rename files
145n/a continue
146n/a
147n/a if preserve_symlinks and os.path.islink(src_name):
148n/a link_dest = os.readlink(src_name)
149n/a if verbose >= 1:
150n/a log.info("linking %s -> %s", dst_name, link_dest)
151n/a if not dry_run:
152n/a os.symlink(link_dest, dst_name)
153n/a outputs.append(dst_name)
154n/a
155n/a elif os.path.isdir(src_name):
156n/a outputs.extend(
157n/a copy_tree(src_name, dst_name, preserve_mode,
158n/a preserve_times, preserve_symlinks, update,
159n/a verbose=verbose, dry_run=dry_run))
160n/a else:
161n/a copy_file(src_name, dst_name, preserve_mode,
162n/a preserve_times, update, verbose=verbose,
163n/a dry_run=dry_run)
164n/a outputs.append(dst_name)
165n/a
166n/a return outputs
167n/a
168n/adef _build_cmdtuple(path, cmdtuples):
169n/a """Helper for remove_tree()."""
170n/a for f in os.listdir(path):
171n/a real_f = os.path.join(path,f)
172n/a if os.path.isdir(real_f) and not os.path.islink(real_f):
173n/a _build_cmdtuple(real_f, cmdtuples)
174n/a else:
175n/a cmdtuples.append((os.remove, real_f))
176n/a cmdtuples.append((os.rmdir, path))
177n/a
178n/adef remove_tree(directory, verbose=1, dry_run=0):
179n/a """Recursively remove an entire directory tree.
180n/a
181n/a Any errors are ignored (apart from being reported to stdout if 'verbose'
182n/a is true).
183n/a """
184n/a global _path_created
185n/a
186n/a if verbose >= 1:
187n/a log.info("removing '%s' (and everything under it)", directory)
188n/a if dry_run:
189n/a return
190n/a cmdtuples = []
191n/a _build_cmdtuple(directory, cmdtuples)
192n/a for cmd in cmdtuples:
193n/a try:
194n/a cmd[0](cmd[1])
195n/a # remove dir from cache if it's already there
196n/a abspath = os.path.abspath(cmd[1])
197n/a if abspath in _path_created:
198n/a del _path_created[abspath]
199n/a except OSError as exc:
200n/a log.warn("error removing %s: %s", directory, exc)
201n/a
202n/adef ensure_relative(path):
203n/a """Take the full path 'path', and make it a relative path.
204n/a
205n/a This is useful to make 'path' the second argument to os.path.join().
206n/a """
207n/a drive, path = os.path.splitdrive(path)
208n/a if path[0:1] == os.sep:
209n/a path = drive + path[1:]
210n/a return path