blob: f4a1df791ff7d03d2d8d33b89f004e47be9e1a9c [file] [log] [blame]
Greg Ward2689e3d1999-03-22 14:52:19 +00001"""distutils.util
2
3General-purpose utility functions used throughout the Distutils
4(especially in command classes). Mostly filesystem manipulation, but
5not limited to that. The functions in this module generally raise
6DistutilsFileError when they have problems with the filesystem, because
7os.error in pre-1.5.2 Python only gives the error message and not the
8file causing it."""
9
10# created 1999/03/08, Greg Ward
11
12__rcsid__ = "$Id$"
13
14import os
15from distutils.errors import *
16
17
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).
Greg Warde765a3b1999-04-04 02:54:20 +000021def mkpath (name, mode=0777, verbose=0, dry_run=0):
Greg Ward2689e3d1999-03-22 14:52:19 +000022 """Create a directory and any missing ancestor directories. If the
23 directory already exists, return silently. Raise
24 DistutilsFileError if unable to create some directory along the
25 way (eg. some sub-path exists, but is a file rather than a
26 directory). If 'verbose' is true, print a one-line summary of
27 each mkdir to stdout."""
28
29 # XXX what's the better way to handle verbosity? print as we create
30 # each directory in the path (the current behaviour), or only announce
31 # the creation of the whole path, and force verbose=0 on all sub-calls?
32
33 if os.path.isdir (name):
34 return
35
36 (head, tail) = os.path.split (name)
37 tails = [tail] # stack of lone dirs to create
38
39 while head and tail and not os.path.isdir (head):
40 #print "splitting '%s': " % head,
41 (head, tail) = os.path.split (head)
42 #print "to ('%s','%s')" % (head, tail)
43 tails.insert (0, tail) # push next higher dir onto stack
44
45 #print "stack of tails:", tails
46
Greg Warde765a3b1999-04-04 02:54:20 +000047 # now 'head' contains the deepest directory that already exists
48 # (that is, the child of 'head' in 'name' is the highest directory
49 # that does *not* exist)
Greg Ward2689e3d1999-03-22 14:52:19 +000050 for d in tails:
51 #print "head = %s, d = %s: " % (head, d),
52 head = os.path.join (head, d)
53 if verbose:
54 print "creating", head
Greg Warde765a3b1999-04-04 02:54:20 +000055
56 if not dry_run:
57 try:
58 os.mkdir (head)
59 except os.error, (errno, errstr):
60 raise DistutilsFileError, "%s: %s" % (head, errstr)
Greg Ward2689e3d1999-03-22 14:52:19 +000061
62# mkpath ()
63
64
65def newer (file1, file2):
66 """Return true if file1 exists and is more recently modified than
67 file2, or if file1 exists and file2 doesn't. Return false if both
68 exist and file2 is the same age or younger than file1. Raises
69 DistutilsFileError if file1 does not exist."""
70
71 if not os.path.exists (file1):
72 raise DistutilsFileError, "file '%s' does not exist" % file1
73 if not os.path.exists (file2):
74 return 1
75
76 from stat import *
77 mtime1 = os.stat(file1)[ST_MTIME]
78 mtime2 = os.stat(file2)[ST_MTIME]
79
80 return mtime1 > mtime2
81
82# newer ()
83
84
85def make_file (src, dst, func, args,
86 verbose=0, update_message=None, noupdate_message=None):
87 """Makes 'dst' from 'src' (both filenames) by calling 'func' with
88 'args', but only if it needs to: i.e. if 'dst' does not exist or
89 'src' is newer than 'dst'."""
90
91 if newer (src, dst):
92 if verbose and update_message:
93 print update_message
94 apply (func, args)
95 else:
96 if verbose and noupdate_message:
97 print noupdate_message
98
99# make_file ()
100
101
102def _copy_file_contents (src, dst, buffer_size=16*1024):
103 """Copy the file 'src' to 'dst'; both must be filenames. Any error
104 opening either file, reading from 'src', or writing to 'dst',
105 raises DistutilsFileError. Data is read/written in chunks of
106 'buffer_size' bytes (default 16k). No attempt is made to handle
107 anything apart from regular files."""
108
109 # Stolen from shutil module in the standard library, but with
110 # custom error-handling added.
111
112 fsrc = None
113 fdst = None
114 try:
115 try:
116 fsrc = open(src, 'rb')
117 except os.error, (errno, errstr):
118 raise DistutilsFileError, "could not open %s: %s" % (src, errstr)
119
120 try:
121 fdst = open(dst, 'wb')
122 except os.error, (errno, errstr):
123 raise DistutilsFileError, "could not create %s: %s" % (dst, errstr)
124
125 while 1:
126 try:
127 buf = fsrc.read (buffer_size)
128 except os.error, (errno, errstr):
129 raise DistutilsFileError, \
130 "could not read from %s: %s" % (src, errstr)
131
132 if not buf:
133 break
134
135 try:
136 fdst.write(buf)
137 except os.error, (errno, errstr):
138 raise DistutilsFileError, \
139 "could not write to %s: %s" % (dst, errstr)
140
141 finally:
142 if fdst:
143 fdst.close()
144 if fsrc:
145 fsrc.close()
146
147# _copy_file_contents()
148
149
150def copy_file (src, dst,
151 preserve_mode=1,
152 preserve_times=1,
153 update=0,
Greg Warde765a3b1999-04-04 02:54:20 +0000154 verbose=0,
155 dry_run=0):
Greg Ward2689e3d1999-03-22 14:52:19 +0000156
157 """Copy a file 'src' to 'dst'. If 'dst' is a directory, then 'src'
158 is copied there with the same name; otherwise, it must be a
159 filename. (If the file exists, it will be ruthlessly clobbered.)
160 If 'preserve_mode' is true (the default), the file's mode (type
161 and permission bits, or whatever is analogous on the current
162 platform) is copied. If 'preserve_times' is true (the default),
163 the last-modified and last-access times are copied as well. If
164 'update' is true, 'src' will only be copied if 'dst' does not
165 exist, or if 'dst' does exist but is older than 'src'. If
166 'verbose' is true, then a one-line summary of the copy will be
167 printed to stdout."""
168
169 # XXX doesn't copy Mac-specific metadata
170
Greg Ward2689e3d1999-03-22 14:52:19 +0000171 from stat import *
172
173 if not os.path.isfile (src):
174 raise DistutilsFileError, \
175 "can't copy %s:not a regular file" % src
176
177 if os.path.isdir (dst):
178 dir = dst
179 dst = os.path.join (dst, os.path.basename (src))
180 else:
181 dir = os.path.dirname (dst)
182
183 if update and not newer (src, dst):
Greg Warde765a3b1999-04-04 02:54:20 +0000184 print "not copying %s (output up-to-date)" % src
Greg Ward2689e3d1999-03-22 14:52:19 +0000185 return
186
187 if verbose:
188 print "copying %s -> %s" % (src, dir)
189
Greg Warde765a3b1999-04-04 02:54:20 +0000190 if dry_run:
191 return
192
193 _copy_file_contents (src, dst)
Greg Ward2689e3d1999-03-22 14:52:19 +0000194 if preserve_mode or preserve_times:
195 st = os.stat (src)
196 if preserve_mode:
197 os.chmod (dst, S_IMODE (st[ST_MODE]))
198 if preserve_times:
199 os.utime (dst, (st[ST_ATIME], st[ST_MTIME]))
200
201# copy_file ()
202
203
204def copy_tree (src, dst,
205 preserve_mode=1,
206 preserve_times=1,
207 preserve_symlinks=0,
208 update=0,
Greg Warde765a3b1999-04-04 02:54:20 +0000209 verbose=0,
210 dry_run=0):
211
Greg Ward2689e3d1999-03-22 14:52:19 +0000212
213 """Copy an entire directory tree 'src' to a new location 'dst'. Both
214 'src' and 'dst' must be directory names. If 'src' is not a
215 directory, raise DistutilsFileError. If 'dst' does not exist, it
216 is created with 'mkpath'. The endresult of the copy is that
217 every file in 'src' is copied to 'dst', and directories under
218 'src' are recursively copied to 'dst'.
219
220 'preserve_mode' and 'preserve_times' are the same as for
221 'copy_file'; note that they only apply to regular files, not to
222 directories. If 'preserve_symlinks' is true, symlinks will be
223 copied as symlinks (on platforms that support them!); otherwise
224 (the default), the destination of the symlink will be copied.
225 'update' and 'verbose' are the same as for 'copy_file'."""
226
227 if not os.path.isdir (src):
228 raise DistutilsFileError, \
229 "cannot copy tree %s: not a directory" % src
230 try:
231 names = os.listdir (src)
232 except os.error, (errno, errstr):
233 raise DistutilsFileError, \
234 "error listing files in %s: %s" % (src, errstr)
235
Greg Warde765a3b1999-04-04 02:54:20 +0000236 if not dry_run:
237 mkpath (dst, verbose=verbose)
Greg Ward2689e3d1999-03-22 14:52:19 +0000238
239 for n in names:
240 src_name = os.path.join (src, n)
241 dst_name = os.path.join (dst, n)
242
243 if preserve_symlinks and os.path.islink (src_name):
244 link_dest = os.readlink (src_name)
Greg Warde765a3b1999-04-04 02:54:20 +0000245 if verbose:
246 print "linking %s -> %s" % (dst_name, link_dest)
247 if not dry_run:
248 os.symlink (link_dest, dst_name)
Greg Ward2689e3d1999-03-22 14:52:19 +0000249 elif os.path.isdir (src_name):
250 copy_tree (src_name, dst_name,
251 preserve_mode, preserve_times, preserve_symlinks,
Greg Warde765a3b1999-04-04 02:54:20 +0000252 update, verbose, dry_run)
Greg Ward2689e3d1999-03-22 14:52:19 +0000253 else:
254 copy_file (src_name, dst_name,
255 preserve_mode, preserve_times,
Greg Warde765a3b1999-04-04 02:54:20 +0000256 update, verbose, dry_run)
Greg Ward2689e3d1999-03-22 14:52:19 +0000257
258# copy_tree ()