blob: 4f93cd44d5f5bcbbfc3e1a5f87e6a4898b5d4120 [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
Greg Wardac1424a1999-09-21 18:37:51 +000018# cache for by mkpath() -- in addition to cheapening redundant calls,
19# eliminates redundant "creating /foo/bar/baz" messages in dry-run mode
20PATH_CREATED = {}
21
Greg Ward2689e3d1999-03-22 14:52:19 +000022# I don't use os.makedirs because a) it's new to Python 1.5.2, and
23# b) it blows up if the directory already exists (I want to silently
24# succeed in that case).
Greg Warde765a3b1999-04-04 02:54:20 +000025def mkpath (name, mode=0777, verbose=0, dry_run=0):
Greg Ward2689e3d1999-03-22 14:52:19 +000026 """Create a directory and any missing ancestor directories. If the
27 directory already exists, return silently. Raise
28 DistutilsFileError if unable to create some directory along the
29 way (eg. some sub-path exists, but is a file rather than a
30 directory). If 'verbose' is true, print a one-line summary of
31 each mkdir to stdout."""
32
Greg Wardac1424a1999-09-21 18:37:51 +000033 global PATH_CREATED
34
Greg Ward2689e3d1999-03-22 14:52:19 +000035 # XXX what's the better way to handle verbosity? print as we create
36 # each directory in the path (the current behaviour), or only announce
Greg Wardac1424a1999-09-21 18:37:51 +000037 # the creation of the whole path? (quite easy to do the latter since
38 # we're not using a recursive algorithm)
Greg Ward2689e3d1999-03-22 14:52:19 +000039
Greg Wardf3b997a1999-10-03 20:50:41 +000040 name = os.path.normpath (name)
41
Greg Ward2689e3d1999-03-22 14:52:19 +000042 if os.path.isdir (name):
43 return
Greg Wardac1424a1999-09-21 18:37:51 +000044 if PATH_CREATED.get (name):
45 return
Greg Ward2689e3d1999-03-22 14:52:19 +000046
47 (head, tail) = os.path.split (name)
48 tails = [tail] # stack of lone dirs to create
49
50 while head and tail and not os.path.isdir (head):
51 #print "splitting '%s': " % head,
52 (head, tail) = os.path.split (head)
53 #print "to ('%s','%s')" % (head, tail)
54 tails.insert (0, tail) # push next higher dir onto stack
55
56 #print "stack of tails:", tails
57
Greg Warde765a3b1999-04-04 02:54:20 +000058 # now 'head' contains the deepest directory that already exists
59 # (that is, the child of 'head' in 'name' is the highest directory
60 # that does *not* exist)
Greg Ward2689e3d1999-03-22 14:52:19 +000061 for d in tails:
62 #print "head = %s, d = %s: " % (head, d),
63 head = os.path.join (head, d)
Greg Wardcd1486f1999-09-29 12:14:16 +000064 if PATH_CREATED.get (head):
65 continue
66
Greg Ward2689e3d1999-03-22 14:52:19 +000067 if verbose:
68 print "creating", head
Greg Warde765a3b1999-04-04 02:54:20 +000069
70 if not dry_run:
71 try:
72 os.mkdir (head)
73 except os.error, (errno, errstr):
74 raise DistutilsFileError, "%s: %s" % (head, errstr)
Greg Ward2689e3d1999-03-22 14:52:19 +000075
Greg Wardac1424a1999-09-21 18:37:51 +000076 PATH_CREATED[head] = 1
77
Greg Ward2689e3d1999-03-22 14:52:19 +000078# mkpath ()
79
80
Greg Ward138ce651999-09-13 03:09:38 +000081def newer (source, target):
82 """Return true if 'source' exists and is more recently modified than
83 'target', or if 'source' exists and 'target' doesn't. Return
84 false if both exist and 'target' is the same age or younger than
85 'source'. Raise DistutilsFileError if 'source' does not
86 exist."""
Greg Ward2689e3d1999-03-22 14:52:19 +000087
Greg Ward138ce651999-09-13 03:09:38 +000088 if not os.path.exists (source):
89 raise DistutilsFileError, "file '%s' does not exist" % source
90 if not os.path.exists (target):
Greg Ward2689e3d1999-03-22 14:52:19 +000091 return 1
92
Greg Ward138ce651999-09-13 03:09:38 +000093 from stat import ST_MTIME
94 mtime1 = os.stat(source)[ST_MTIME]
95 mtime2 = os.stat(target)[ST_MTIME]
Greg Ward2689e3d1999-03-22 14:52:19 +000096
97 return mtime1 > mtime2
98
99# newer ()
100
101
Greg Ward138ce651999-09-13 03:09:38 +0000102def newer_pairwise (sources, targets):
Greg Ward138ce651999-09-13 03:09:38 +0000103 """Walk two filename lists in parallel, testing if each 'target' is
104 up-to-date relative to its corresponding 'source'. If so, both
105 are deleted from their respective lists. Return a list of tuples
106 containing the deleted (source,target) pairs."""
107
108 if len (sources) != len (targets):
109 raise ValueError, "'sources' and 'targets' must be same length"
110
111 goners = []
112 for i in range (len (sources)-1, -1, -1):
113 if not newer (sources[i], targets[i]):
114 goners.append ((sources[i], targets[i]))
115 del sources[i]
116 del targets[i]
117 goners.reverse()
118 return goners
119
120# newer_pairwise ()
121
122
123def newer_group (sources, target):
124 """Return true if 'target' is out-of-date with respect to any
125 file listed in 'sources'. In other words, if 'target' exists and
126 is newer than every file in 'sources', return false; otherwise
127 return true."""
128
129 # If the target doesn't even exist, then it's definitely out-of-date.
130 if not os.path.exists (target):
131 return 1
132
133 # Otherwise we have to find out the hard way: if *any* source file
134 # is more recent than 'target', then 'target' is out-of-date and
135 # we can immediately return true. If we fall through to the end
136 # of the loop, then 'target' is up-to-date and we return false.
137 from stat import ST_MTIME
138 target_mtime = os.stat (target)[ST_MTIME]
139 for source in sources:
140 source_mtime = os.stat(source)[ST_MTIME]
141 if source_mtime > target_mtime:
142 return 1
143 else:
144 return 0
145
146# newer_group ()
147
148
Greg Wardf3b997a1999-10-03 20:50:41 +0000149# XXX this isn't used anywhere, and worse, it has the same name as a method
150# in Command with subtly different semantics. (This one just has one
151# source -> one dest; that one has many sources -> one dest.) Nuke it?
Greg Ward2689e3d1999-03-22 14:52:19 +0000152def make_file (src, dst, func, args,
153 verbose=0, update_message=None, noupdate_message=None):
154 """Makes 'dst' from 'src' (both filenames) by calling 'func' with
155 'args', but only if it needs to: i.e. if 'dst' does not exist or
156 'src' is newer than 'dst'."""
157
158 if newer (src, dst):
159 if verbose and update_message:
160 print update_message
161 apply (func, args)
162 else:
163 if verbose and noupdate_message:
164 print noupdate_message
165
166# make_file ()
167
168
169def _copy_file_contents (src, dst, buffer_size=16*1024):
170 """Copy the file 'src' to 'dst'; both must be filenames. Any error
171 opening either file, reading from 'src', or writing to 'dst',
172 raises DistutilsFileError. Data is read/written in chunks of
173 'buffer_size' bytes (default 16k). No attempt is made to handle
174 anything apart from regular files."""
175
176 # Stolen from shutil module in the standard library, but with
177 # custom error-handling added.
178
179 fsrc = None
180 fdst = None
181 try:
182 try:
183 fsrc = open(src, 'rb')
184 except os.error, (errno, errstr):
185 raise DistutilsFileError, "could not open %s: %s" % (src, errstr)
186
187 try:
188 fdst = open(dst, 'wb')
189 except os.error, (errno, errstr):
190 raise DistutilsFileError, "could not create %s: %s" % (dst, errstr)
191
192 while 1:
193 try:
194 buf = fsrc.read (buffer_size)
195 except os.error, (errno, errstr):
196 raise DistutilsFileError, \
197 "could not read from %s: %s" % (src, errstr)
198
199 if not buf:
200 break
201
202 try:
203 fdst.write(buf)
204 except os.error, (errno, errstr):
205 raise DistutilsFileError, \
206 "could not write to %s: %s" % (dst, errstr)
207
208 finally:
209 if fdst:
210 fdst.close()
211 if fsrc:
212 fsrc.close()
213
214# _copy_file_contents()
215
216
217def copy_file (src, dst,
218 preserve_mode=1,
219 preserve_times=1,
220 update=0,
Greg Warde765a3b1999-04-04 02:54:20 +0000221 verbose=0,
222 dry_run=0):
Greg Ward2689e3d1999-03-22 14:52:19 +0000223
224 """Copy a file 'src' to 'dst'. If 'dst' is a directory, then 'src'
225 is copied there with the same name; otherwise, it must be a
226 filename. (If the file exists, it will be ruthlessly clobbered.)
227 If 'preserve_mode' is true (the default), the file's mode (type
228 and permission bits, or whatever is analogous on the current
229 platform) is copied. If 'preserve_times' is true (the default),
230 the last-modified and last-access times are copied as well. If
231 'update' is true, 'src' will only be copied if 'dst' does not
232 exist, or if 'dst' does exist but is older than 'src'. If
233 'verbose' is true, then a one-line summary of the copy will be
Greg Ward884df451999-05-02 21:42:05 +0000234 printed to stdout.
235
236 Return true if the file was copied (or would have been copied),
237 false otherwise (ie. 'update' was true and the destination is
238 up-to-date)."""
Greg Ward2689e3d1999-03-22 14:52:19 +0000239
240 # XXX doesn't copy Mac-specific metadata
241
Greg Ward2689e3d1999-03-22 14:52:19 +0000242 from stat import *
243
244 if not os.path.isfile (src):
245 raise DistutilsFileError, \
Greg Ward138ce651999-09-13 03:09:38 +0000246 "can't copy %s: not a regular file" % src
Greg Ward2689e3d1999-03-22 14:52:19 +0000247
248 if os.path.isdir (dst):
249 dir = dst
250 dst = os.path.join (dst, os.path.basename (src))
251 else:
252 dir = os.path.dirname (dst)
253
254 if update and not newer (src, dst):
Greg Ward884df451999-05-02 21:42:05 +0000255 if verbose:
256 print "not copying %s (output up-to-date)" % src
257 return 0
Greg Ward2689e3d1999-03-22 14:52:19 +0000258
259 if verbose:
260 print "copying %s -> %s" % (src, dir)
261
Greg Warde765a3b1999-04-04 02:54:20 +0000262 if dry_run:
Greg Ward884df451999-05-02 21:42:05 +0000263 return 1
Greg Warde765a3b1999-04-04 02:54:20 +0000264
265 _copy_file_contents (src, dst)
Greg Ward2689e3d1999-03-22 14:52:19 +0000266 if preserve_mode or preserve_times:
267 st = os.stat (src)
Greg Ward5116f901999-06-08 17:05:21 +0000268
269 # According to David Ascher <da@ski.org>, utime() should be done
270 # before chmod() (at least under NT).
Greg Ward2689e3d1999-03-22 14:52:19 +0000271 if preserve_times:
272 os.utime (dst, (st[ST_ATIME], st[ST_MTIME]))
Greg Ward5116f901999-06-08 17:05:21 +0000273 if preserve_mode:
274 os.chmod (dst, S_IMODE (st[ST_MODE]))
Greg Ward2689e3d1999-03-22 14:52:19 +0000275
Greg Ward884df451999-05-02 21:42:05 +0000276 return 1
277
Greg Ward2689e3d1999-03-22 14:52:19 +0000278# copy_file ()
279
280
281def copy_tree (src, dst,
282 preserve_mode=1,
283 preserve_times=1,
284 preserve_symlinks=0,
285 update=0,
Greg Warde765a3b1999-04-04 02:54:20 +0000286 verbose=0,
287 dry_run=0):
288
Greg Ward2689e3d1999-03-22 14:52:19 +0000289
290 """Copy an entire directory tree 'src' to a new location 'dst'. Both
291 'src' and 'dst' must be directory names. If 'src' is not a
292 directory, raise DistutilsFileError. If 'dst' does not exist, it
Greg Wardf3b997a1999-10-03 20:50:41 +0000293 is created with 'mkpath()'. The end result of the copy is that
Greg Ward2689e3d1999-03-22 14:52:19 +0000294 every file in 'src' is copied to 'dst', and directories under
Greg Ward884df451999-05-02 21:42:05 +0000295 'src' are recursively copied to 'dst'. Return the list of files
296 copied (under their output names) -- note that if 'update' is true,
297 this might be less than the list of files considered. Return
298 value is not affected by 'dry_run'.
Greg Ward2689e3d1999-03-22 14:52:19 +0000299
300 'preserve_mode' and 'preserve_times' are the same as for
301 'copy_file'; note that they only apply to regular files, not to
302 directories. If 'preserve_symlinks' is true, symlinks will be
303 copied as symlinks (on platforms that support them!); otherwise
304 (the default), the destination of the symlink will be copied.
305 'update' and 'verbose' are the same as for 'copy_file'."""
306
Greg Ward138ce651999-09-13 03:09:38 +0000307 if not dry_run and not os.path.isdir (src):
Greg Ward2689e3d1999-03-22 14:52:19 +0000308 raise DistutilsFileError, \
309 "cannot copy tree %s: not a directory" % src
310 try:
311 names = os.listdir (src)
312 except os.error, (errno, errstr):
Greg Ward138ce651999-09-13 03:09:38 +0000313 if dry_run:
314 names = []
315 else:
316 raise DistutilsFileError, \
317 "error listing files in %s: %s" % (src, errstr)
Greg Ward2689e3d1999-03-22 14:52:19 +0000318
Greg Warde765a3b1999-04-04 02:54:20 +0000319 if not dry_run:
320 mkpath (dst, verbose=verbose)
Greg Ward2689e3d1999-03-22 14:52:19 +0000321
Greg Ward884df451999-05-02 21:42:05 +0000322 outputs = []
323
Greg Ward2689e3d1999-03-22 14:52:19 +0000324 for n in names:
325 src_name = os.path.join (src, n)
326 dst_name = os.path.join (dst, n)
327
328 if preserve_symlinks and os.path.islink (src_name):
329 link_dest = os.readlink (src_name)
Greg Warde765a3b1999-04-04 02:54:20 +0000330 if verbose:
331 print "linking %s -> %s" % (dst_name, link_dest)
332 if not dry_run:
333 os.symlink (link_dest, dst_name)
Greg Ward884df451999-05-02 21:42:05 +0000334 outputs.append (dst_name)
335
Greg Ward2689e3d1999-03-22 14:52:19 +0000336 elif os.path.isdir (src_name):
Greg Ward884df451999-05-02 21:42:05 +0000337 outputs[-1:] = \
338 copy_tree (src_name, dst_name,
339 preserve_mode, preserve_times, preserve_symlinks,
340 update, verbose, dry_run)
Greg Ward2689e3d1999-03-22 14:52:19 +0000341 else:
Greg Ward884df451999-05-02 21:42:05 +0000342 if (copy_file (src_name, dst_name,
343 preserve_mode, preserve_times,
344 update, verbose, dry_run)):
345 outputs.append (dst_name)
346
347 return outputs
Greg Ward2689e3d1999-03-22 14:52:19 +0000348
349# copy_tree ()
Greg Ward138ce651999-09-13 03:09:38 +0000350
351
352# XXX I suspect this is Unix-specific -- need porting help!
353def move_file (src, dst,
354 verbose=0,
355 dry_run=0):
356
357 """Move a file 'src' to 'dst'. If 'dst' is a directory, the file
358 will be moved into it with the same name; otherwise, 'src' is
359 just renamed to 'dst'. Return the new full name of the file.
360
361 Handles cross-device moves on Unix using
362 'copy_file()'. What about other systems???"""
363
364 from os.path import exists, isfile, isdir, basename, dirname
365
366 if verbose:
367 print "moving %s -> %s" % (src, dst)
368
369 if dry_run:
370 return dst
371
372 if not isfile (src):
373 raise DistutilsFileError, \
374 "can't move '%s': not a regular file" % src
375
376 if isdir (dst):
377 dst = os.path.join (dst, basename (src))
378 elif exists (dst):
379 raise DistutilsFileError, \
380 "can't move '%s': destination '%s' already exists" % \
381 (src, dst)
382
383 if not isdir (dirname (dst)):
384 raise DistutilsFileError, \
385 "can't move '%s': destination '%s' not a valid path" % \
386 (src, dst)
387
388 copy_it = 0
389 try:
390 os.rename (src, dst)
391 except os.error, (num, msg):
392 if num == errno.EXDEV:
393 copy_it = 1
394 else:
395 raise DistutilsFileError, \
396 "couldn't move '%s' to '%s': %s" % (src, dst, msg)
397
398 if copy_it:
399 copy_file (src, dst)
400 try:
401 os.unlink (src)
402 except os.error, (num, msg):
403 try:
404 os.unlink (dst)
405 except os.error:
406 pass
407 raise DistutilsFileError, \
408 ("couldn't move '%s' to '%s' by copy/delete: " +
409 "delete '%s' failed: %s") % \
410 (src, dst, src, msg)
411
412 return dst
413
414# move_file ()
Greg Wardac1424a1999-09-21 18:37:51 +0000415
416
417def write_file (filename, contents):
Greg Wardf3b997a1999-10-03 20:50:41 +0000418 """Create a file with the specified name and write 'contents' (a
Greg Wardac1424a1999-09-21 18:37:51 +0000419 sequence of strings without line terminators) to it."""
420
421 f = open (filename, "w")
422 for line in contents:
423 f.write (line + "\n")
424 f.close ()