3 Utility functions for manipulating directories and directory trees."""
5 # created 2000/04/03, Greg Ward (extracted from util.py)
11 from distutils
.errors
import DistutilsFileError
, DistutilsInternalError
14 # cache for by mkpath() -- in addition to cheapening redundant calls,
15 # eliminates redundant "creating /foo/bar/baz" messages in dry-run mode
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).
21 def 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
33 # 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`
38 # 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)
43 name
= os
.path
.normpath(name
)
45 if os
.path
.isdir(name
) or name
== '':
47 if _path_created
.get(os
.path
.abspath(name
)):
50 (head
, tail
) = os
.path
.split(name
)
51 tails
= [tail
] # stack of lone dirs to create
53 while head
and tail
and not os
.path
.isdir(head
):
54 #print "splitting '%s': " % head,
55 (head
, tail
) = os
.path
.split(head
)
56 #print "to ('%s','%s')" % (head, tail)
57 tails
.insert(0, tail
) # push next higher dir onto stack
59 #print "stack of tails:", tails
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)
65 #print "head = %s, d = %s: " % (head, d),
66 head
= os
.path
.join(head
, d
)
67 abs_head
= os
.path
.abspath(head
)
69 if _path_created
.get(abs_head
):
73 print "creating", head
78 created_dirs
.append(head
)
80 raise DistutilsFileError
, \
81 "could not create '%s': %s" % (head
, exc
[-1])
83 _path_created
[abs_head
] = 1
89 def create_tree (base_dir
, files
, mode
=0777, verbose
=0, dry_run
=0):
91 """Create all the empty directories under 'base_dir' needed to
92 put 'files' there. 'base_dir' is just the a name of a directory
93 which doesn't necessarily exist yet; 'files' is a list of filenames
94 to be interpreted relative to 'base_dir'. 'base_dir' + the
95 directory portion of every file in 'files' will be created if it
96 doesn't already exist. 'mode', 'verbose' and 'dry_run' flags are as
99 # First get the list of directories to create
102 need_dir
[os
.path
.join(base_dir
, os
.path
.dirname(file))] = 1
103 need_dirs
= need_dir
.keys()
107 for dir in need_dirs
:
108 mkpath(dir, mode
, verbose
, dry_run
)
113 def copy_tree (src
, dst
,
121 """Copy an entire directory tree 'src' to a new location 'dst'. Both
122 'src' and 'dst' must be directory names. If 'src' is not a
123 directory, raise DistutilsFileError. If 'dst' does not exist, it is
124 created with 'mkpath()'. The end result of the copy is that every
125 file in 'src' is copied to 'dst', and directories under 'src' are
126 recursively copied to 'dst'. Return the list of files that were
127 copied or might have been copied, using their output name. The
128 return value is unaffected by 'update' or 'dry_run': it is simply
129 the list of all files under 'src', with the names changed to be
132 'preserve_mode' and 'preserve_times' are the same as for
133 'copy_file'; note that they only apply to regular files, not to
134 directories. If 'preserve_symlinks' is true, symlinks will be
135 copied as symlinks (on platforms that support them!); otherwise
136 (the default), the destination of the symlink will be copied.
137 'update' and 'verbose' are the same as for 'copy_file'."""
139 from distutils
.file_util
import copy_file
141 if not dry_run
and not os
.path
.isdir(src
):
142 raise DistutilsFileError
, \
143 "cannot copy tree '%s': not a directory" % src
145 names
= os
.listdir(src
)
146 except os
.error
, (errno
, errstr
):
150 raise DistutilsFileError
, \
151 "error listing files in '%s': %s" % (src
, errstr
)
154 mkpath(dst
, verbose
=verbose
)
159 src_name
= os
.path
.join(src
, n
)
160 dst_name
= os
.path
.join(dst
, n
)
162 if preserve_symlinks
and os
.path
.islink(src_name
):
163 link_dest
= os
.readlink(src_name
)
165 print "linking %s -> %s" % (dst_name
, link_dest
)
167 os
.symlink(link_dest
, dst_name
)
168 outputs
.append(dst_name
)
170 elif os
.path
.isdir(src_name
):
172 copy_tree(src_name
, dst_name
,
173 preserve_mode
, preserve_times
, preserve_symlinks
,
174 update
, verbose
, dry_run
))
176 copy_file(src_name
, dst_name
,
177 preserve_mode
, preserve_times
,
178 update
, None, verbose
, dry_run
)
179 outputs
.append(dst_name
)
185 # Helper for remove_tree()
186 def _build_cmdtuple(path
, cmdtuples
):
187 for f
in os
.listdir(path
):
188 real_f
= os
.path
.join(path
,f
)
189 if os
.path
.isdir(real_f
) and not os
.path
.islink(real_f
):
190 _build_cmdtuple(real_f
, cmdtuples
)
192 cmdtuples
.append((os
.remove
, real_f
))
193 cmdtuples
.append((os
.rmdir
, path
))
196 def remove_tree (directory
, verbose
=0, dry_run
=0):
197 """Recursively remove an entire directory tree. Any errors are ignored
198 (apart from being reported to stdout if 'verbose' is true).
200 from distutils
.util
import grok_environment_error
204 print "removing '%s' (and everything under it)" % directory
208 _build_cmdtuple(directory
, cmdtuples
)
209 for cmd
in cmdtuples
:
211 apply(cmd
[0], (cmd
[1],))
212 # remove dir from cache if it's already there
213 abspath
= os
.path
.abspath(cmd
[1])
214 if _path_created
.has_key(abspath
):
215 del _path_created
[abspath
]
216 except (IOError, OSError), exc
:
218 print grok_environment_error(
219 exc
, "error removing %s: " % directory
)