blob: 768cb4ebe757cd314df0d1a2f70f5fb593e972a2 [file] [log] [blame]
Greg Wardaebf7062000-04-04 02:05:59 +00001"""distutils.dir_util
2
3Utility functions for manipulating directories and directory trees."""
4
5# created 2000/04/03, Greg Ward (extracted from util.py)
6
7__revision__ = "$Id$"
8
9import os
Greg Ward2d238c52000-05-27 01:35:27 +000010from types import *
11from distutils.errors import DistutilsFileError, DistutilsInternalError
Greg Wardaebf7062000-04-04 02:05:59 +000012
13
14# cache for by mkpath() -- in addition to cheapening redundant calls,
15# eliminates redundant "creating /foo/bar/baz" messages in dry-run mode
Greg Wardb248b7f2000-06-17 02:19:30 +000016_path_created = {}
Greg Wardaebf7062000-04-04 02:05:59 +000017
18# I don't use os.makedirs because a) it's new to Python 1.5.2, and
19# b) it blows up if the directory already exists (I want to silently
20# succeed in that case).
21def mkpath (name, mode=0777, verbose=0, dry_run=0):
22 """Create a directory and any missing ancestor directories. If the
23 directory already exists (or if 'name' is the empty string, which
24 means the current directory, which of course exists), then do
25 nothing. Raise DistutilsFileError if unable to create some
26 directory along the way (eg. some sub-path exists, but is a file
27 rather than a directory). If 'verbose' is true, print a one-line
28 summary of each mkdir to stdout. Return the list of directories
29 actually created."""
30
Greg Wardb248b7f2000-06-17 02:19:30 +000031 global _path_created
Greg Wardaebf7062000-04-04 02:05:59 +000032
Greg Ward2d238c52000-05-27 01:35:27 +000033 # Detect a common bug -- name is None
34 if type(name) is not StringType:
35 raise DistutilsInternalError, \
36 "mkpath: 'name' must be a string (got %s)" % `name`
37
Greg Wardaebf7062000-04-04 02:05:59 +000038 # XXX what's the better way to handle verbosity? print as we create
39 # each directory in the path (the current behaviour), or only announce
40 # the creation of the whole path? (quite easy to do the latter since
41 # we're not using a recursive algorithm)
42
Greg Ward071ed762000-09-26 02:12:31 +000043 name = os.path.normpath(name)
Greg Wardaebf7062000-04-04 02:05:59 +000044 created_dirs = []
Greg Ward071ed762000-09-26 02:12:31 +000045 if os.path.isdir(name) or name == '':
Greg Wardaebf7062000-04-04 02:05:59 +000046 return created_dirs
Greg Ward071ed762000-09-26 02:12:31 +000047 if _path_created.get(name):
Greg Wardaebf7062000-04-04 02:05:59 +000048 return created_dirs
49
Greg Ward071ed762000-09-26 02:12:31 +000050 (head, tail) = os.path.split(name)
Greg Wardaebf7062000-04-04 02:05:59 +000051 tails = [tail] # stack of lone dirs to create
52
Greg Ward071ed762000-09-26 02:12:31 +000053 while head and tail and not os.path.isdir(head):
Greg Wardaebf7062000-04-04 02:05:59 +000054 #print "splitting '%s': " % head,
Greg Ward071ed762000-09-26 02:12:31 +000055 (head, tail) = os.path.split(head)
Greg Wardaebf7062000-04-04 02:05:59 +000056 #print "to ('%s','%s')" % (head, tail)
Greg Ward071ed762000-09-26 02:12:31 +000057 tails.insert(0, tail) # push next higher dir onto stack
Greg Wardaebf7062000-04-04 02:05:59 +000058
59 #print "stack of tails:", tails
60
61 # now 'head' contains the deepest directory that already exists
62 # (that is, the child of 'head' in 'name' is the highest directory
63 # that does *not* exist)
64 for d in tails:
65 #print "head = %s, d = %s: " % (head, d),
Greg Ward071ed762000-09-26 02:12:31 +000066 head = os.path.join(head, d)
67 if _path_created.get(head):
Greg Wardaebf7062000-04-04 02:05:59 +000068 continue
69
70 if verbose:
71 print "creating", head
72
73 if not dry_run:
74 try:
Greg Ward071ed762000-09-26 02:12:31 +000075 os.mkdir(head)
Greg Wardaebf7062000-04-04 02:05:59 +000076 created_dirs.append(head)
77 except OSError, exc:
78 raise DistutilsFileError, \
79 "could not create '%s': %s" % (head, exc[-1])
80
Greg Wardb248b7f2000-06-17 02:19:30 +000081 _path_created[head] = 1
Greg Wardaebf7062000-04-04 02:05:59 +000082 return created_dirs
83
84# mkpath ()
85
86
87def create_tree (base_dir, files, mode=0777, verbose=0, dry_run=0):
88
89 """Create all the empty directories under 'base_dir' needed to
90 put 'files' there. 'base_dir' is just the a name of a directory
91 which doesn't necessarily exist yet; 'files' is a list of filenames
92 to be interpreted relative to 'base_dir'. 'base_dir' + the
93 directory portion of every file in 'files' will be created if it
94 doesn't already exist. 'mode', 'verbose' and 'dry_run' flags are as
95 for 'mkpath()'."""
96
97 # First get the list of directories to create
98 need_dir = {}
99 for file in files:
Greg Ward071ed762000-09-26 02:12:31 +0000100 need_dir[os.path.join(base_dir, os.path.dirname(file))] = 1
Greg Wardaebf7062000-04-04 02:05:59 +0000101 need_dirs = need_dir.keys()
102 need_dirs.sort()
103
104 # Now create them
105 for dir in need_dirs:
Greg Ward071ed762000-09-26 02:12:31 +0000106 mkpath(dir, mode, verbose, dry_run)
Greg Wardaebf7062000-04-04 02:05:59 +0000107
108# create_tree ()
109
110
111def copy_tree (src, dst,
112 preserve_mode=1,
113 preserve_times=1,
114 preserve_symlinks=0,
115 update=0,
116 verbose=0,
117 dry_run=0):
118
119 """Copy an entire directory tree 'src' to a new location 'dst'. Both
120 'src' and 'dst' must be directory names. If 'src' is not a
121 directory, raise DistutilsFileError. If 'dst' does not exist, it is
122 created with 'mkpath()'. The end result of the copy is that every
123 file in 'src' is copied to 'dst', and directories under 'src' are
124 recursively copied to 'dst'. Return the list of files that were
125 copied or might have been copied, using their output name. The
126 return value is unaffected by 'update' or 'dry_run': it is simply
127 the list of all files under 'src', with the names changed to be
128 under 'dst'.
129
130 'preserve_mode' and 'preserve_times' are the same as for
131 'copy_file'; note that they only apply to regular files, not to
132 directories. If 'preserve_symlinks' is true, symlinks will be
133 copied as symlinks (on platforms that support them!); otherwise
134 (the default), the destination of the symlink will be copied.
135 'update' and 'verbose' are the same as for 'copy_file'."""
136
137 from distutils.file_util import copy_file
138
Greg Ward071ed762000-09-26 02:12:31 +0000139 if not dry_run and not os.path.isdir(src):
Greg Wardaebf7062000-04-04 02:05:59 +0000140 raise DistutilsFileError, \
141 "cannot copy tree '%s': not a directory" % src
142 try:
Greg Ward071ed762000-09-26 02:12:31 +0000143 names = os.listdir(src)
Greg Wardaebf7062000-04-04 02:05:59 +0000144 except os.error, (errno, errstr):
145 if dry_run:
146 names = []
147 else:
148 raise DistutilsFileError, \
149 "error listing files in '%s': %s" % (src, errstr)
150
151 if not dry_run:
Greg Ward071ed762000-09-26 02:12:31 +0000152 mkpath(dst, verbose=verbose)
Greg Wardaebf7062000-04-04 02:05:59 +0000153
154 outputs = []
155
156 for n in names:
Greg Ward071ed762000-09-26 02:12:31 +0000157 src_name = os.path.join(src, n)
158 dst_name = os.path.join(dst, n)
Greg Wardaebf7062000-04-04 02:05:59 +0000159
Greg Ward071ed762000-09-26 02:12:31 +0000160 if preserve_symlinks and os.path.islink(src_name):
161 link_dest = os.readlink(src_name)
Greg Wardaebf7062000-04-04 02:05:59 +0000162 if verbose:
163 print "linking %s -> %s" % (dst_name, link_dest)
164 if not dry_run:
Greg Ward071ed762000-09-26 02:12:31 +0000165 os.symlink(link_dest, dst_name)
166 outputs.append(dst_name)
Greg Wardaebf7062000-04-04 02:05:59 +0000167
Greg Ward071ed762000-09-26 02:12:31 +0000168 elif os.path.isdir(src_name):
169 outputs.extend(
170 copy_tree(src_name, dst_name,
171 preserve_mode, preserve_times, preserve_symlinks,
172 update, verbose, dry_run))
Greg Wardaebf7062000-04-04 02:05:59 +0000173 else:
Greg Ward071ed762000-09-26 02:12:31 +0000174 copy_file(src_name, dst_name,
175 preserve_mode, preserve_times,
176 update, None, verbose, dry_run)
177 outputs.append(dst_name)
Greg Wardaebf7062000-04-04 02:05:59 +0000178
179 return outputs
180
181# copy_tree ()
182
Greg Ward039accf2000-06-17 01:58:14 +0000183# Helper for remove_tree()
184def _build_cmdtuple(path, cmdtuples):
185 for f in os.listdir(path):
186 real_f = os.path.join(path,f)
187 if os.path.isdir(real_f) and not os.path.islink(real_f):
188 _build_cmdtuple(real_f, cmdtuples)
189 else:
190 cmdtuples.append((os.remove, real_f))
191 cmdtuples.append((os.rmdir, path))
192
Greg Wardaebf7062000-04-04 02:05:59 +0000193
194def remove_tree (directory, verbose=0, dry_run=0):
195 """Recursively remove an entire directory tree. Any errors are ignored
Greg Wardfcd4f872000-06-17 02:18:19 +0000196 (apart from being reported to stdout if 'verbose' is true).
197 """
198 from distutils.util import grok_environment_error
Greg Wardb248b7f2000-06-17 02:19:30 +0000199 global _path_created
Greg Wardfcd4f872000-06-17 02:18:19 +0000200
Greg Wardaebf7062000-04-04 02:05:59 +0000201 if verbose:
202 print "removing '%s' (and everything under it)" % directory
203 if dry_run:
204 return
Greg Ward039accf2000-06-17 01:58:14 +0000205 cmdtuples = []
206 _build_cmdtuple(directory, cmdtuples)
207 for cmd in cmdtuples:
208 try:
209 apply(cmd[0], (cmd[1],))
210 # remove dir from cache if it's already there
Greg Wardb248b7f2000-06-17 02:19:30 +0000211 if _path_created.has_key(cmd[1]):
212 del _path_created[cmd[1]]
Greg Ward039accf2000-06-17 01:58:14 +0000213 except (IOError, OSError), exc:
214 if verbose:
Greg Wardfcd4f872000-06-17 02:18:19 +0000215 print grok_environment_error(
216 exc, "error removing %s: " % directory)