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