blob: 6674d0aa18e19ae9b615180f6e36eb45129a2f75 [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
Greg Ward3ce77fd2000-03-02 01:49:45 +000012__revision__ = "$Id$"
Greg Ward2689e3d1999-03-22 14:52:19 +000013
Greg Warda7540bd2000-03-23 04:39:16 +000014import sys, os, string, re, shutil
Greg Ward2689e3d1999-03-22 14:52:19 +000015from distutils.errors import *
Greg Ward7c1a6d42000-03-29 02:48:40 +000016from distutils.spawn import spawn
Greg Ward2689e3d1999-03-22 14:52:19 +000017
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 Ward32ce3292000-03-31 03:02:22 +000022# for generating verbose output in 'copy_file()'
23_copy_action = { None: 'copying',
24 'hard': 'hard linking',
25 'sym': 'symbolically linking' }
26
Greg Ward2689e3d1999-03-22 14:52:19 +000027# I don't use os.makedirs because a) it's new to Python 1.5.2, and
28# b) it blows up if the directory already exists (I want to silently
29# succeed in that case).
Greg Warde765a3b1999-04-04 02:54:20 +000030def mkpath (name, mode=0777, verbose=0, dry_run=0):
Greg Ward2689e3d1999-03-22 14:52:19 +000031 """Create a directory and any missing ancestor directories. If the
Greg Ward739d0662000-03-29 02:56:34 +000032 directory already exists (or if 'name' is the empty string, which
33 means the current directory, which of course exists), then do
34 nothing. Raise DistutilsFileError if unable to create some
35 directory along the way (eg. some sub-path exists, but is a file
36 rather than a directory). If 'verbose' is true, print a one-line
37 summary of each mkdir to stdout. Return the list of directories
38 actually created."""
Greg Ward2689e3d1999-03-22 14:52:19 +000039
Greg Wardac1424a1999-09-21 18:37:51 +000040 global PATH_CREATED
41
Greg Ward2689e3d1999-03-22 14:52:19 +000042 # XXX what's the better way to handle verbosity? print as we create
43 # each directory in the path (the current behaviour), or only announce
Greg Wardac1424a1999-09-21 18:37:51 +000044 # the creation of the whole path? (quite easy to do the latter since
45 # we're not using a recursive algorithm)
Greg Ward2689e3d1999-03-22 14:52:19 +000046
Greg Wardf3b997a1999-10-03 20:50:41 +000047 name = os.path.normpath (name)
Greg Wardda4d1ae2000-03-29 02:53:02 +000048 created_dirs = []
Greg Ward96182d72000-03-03 03:00:02 +000049 if os.path.isdir (name) or name == '':
Greg Wardda4d1ae2000-03-29 02:53:02 +000050 return created_dirs
Greg Wardac1424a1999-09-21 18:37:51 +000051 if PATH_CREATED.get (name):
Greg Wardda4d1ae2000-03-29 02:53:02 +000052 return created_dirs
Greg Ward2689e3d1999-03-22 14:52:19 +000053
54 (head, tail) = os.path.split (name)
55 tails = [tail] # stack of lone dirs to create
56
57 while head and tail and not os.path.isdir (head):
58 #print "splitting '%s': " % head,
59 (head, tail) = os.path.split (head)
60 #print "to ('%s','%s')" % (head, tail)
61 tails.insert (0, tail) # push next higher dir onto stack
62
63 #print "stack of tails:", tails
64
Greg Warde765a3b1999-04-04 02:54:20 +000065 # now 'head' contains the deepest directory that already exists
66 # (that is, the child of 'head' in 'name' is the highest directory
67 # that does *not* exist)
Greg Ward2689e3d1999-03-22 14:52:19 +000068 for d in tails:
69 #print "head = %s, d = %s: " % (head, d),
70 head = os.path.join (head, d)
Greg Wardcd1486f1999-09-29 12:14:16 +000071 if PATH_CREATED.get (head):
72 continue
73
Greg Ward2689e3d1999-03-22 14:52:19 +000074 if verbose:
75 print "creating", head
Greg Warde765a3b1999-04-04 02:54:20 +000076
77 if not dry_run:
78 try:
79 os.mkdir (head)
Greg Wardda4d1ae2000-03-29 02:53:02 +000080 created_dirs.append(head)
Greg Ward739d0662000-03-29 02:56:34 +000081 except OSError, exc:
Greg Ward1b4ede52000-03-22 00:22:44 +000082 raise DistutilsFileError, \
Greg Ward739d0662000-03-29 02:56:34 +000083 "could not create '%s': %s" % (head, exc[-1])
Greg Ward2689e3d1999-03-22 14:52:19 +000084
Greg Wardac1424a1999-09-21 18:37:51 +000085 PATH_CREATED[head] = 1
Greg Wardda4d1ae2000-03-29 02:53:02 +000086 return created_dirs
Greg Wardac1424a1999-09-21 18:37:51 +000087
Greg Ward2689e3d1999-03-22 14:52:19 +000088# mkpath ()
89
90
Greg Ward32ce3292000-03-31 03:02:22 +000091def create_tree (base_dir, files, mode=0777, verbose=0, dry_run=0):
92
93 """Create all the empty directories under 'base_dir' needed to
94 put 'files' there. 'base_dir' is just the a name of a directory
95 which doesn't necessarily exist yet; 'files' is a list of filenames
96 to be interpreted relative to 'base_dir'. 'base_dir' + the
97 directory portion of every file in 'files' will be created if it
98 doesn't already exist. 'mode', 'verbose' and 'dry_run' flags are as
99 for 'mkpath()'."""
100
101 # First get the list of directories to create
102 need_dir = {}
103 for file in files:
104 need_dir[os.path.join (base_dir, os.path.dirname (file))] = 1
105 need_dirs = need_dir.keys()
106 need_dirs.sort()
107
108 # Now create them
109 for dir in need_dirs:
110 mkpath (dir, mode, verbose, dry_run)
111
112# create_tree ()
113
114
Greg Ward138ce651999-09-13 03:09:38 +0000115def newer (source, target):
116 """Return true if 'source' exists and is more recently modified than
117 'target', or if 'source' exists and 'target' doesn't. Return
118 false if both exist and 'target' is the same age or younger than
119 'source'. Raise DistutilsFileError if 'source' does not
120 exist."""
Greg Ward2689e3d1999-03-22 14:52:19 +0000121
Greg Ward138ce651999-09-13 03:09:38 +0000122 if not os.path.exists (source):
123 raise DistutilsFileError, "file '%s' does not exist" % source
124 if not os.path.exists (target):
Greg Ward2689e3d1999-03-22 14:52:19 +0000125 return 1
126
Greg Ward138ce651999-09-13 03:09:38 +0000127 from stat import ST_MTIME
128 mtime1 = os.stat(source)[ST_MTIME]
129 mtime2 = os.stat(target)[ST_MTIME]
Greg Ward2689e3d1999-03-22 14:52:19 +0000130
131 return mtime1 > mtime2
132
133# newer ()
134
135
Greg Ward138ce651999-09-13 03:09:38 +0000136def newer_pairwise (sources, targets):
Greg Ward95526652000-03-06 03:44:32 +0000137 """Walk two filename lists in parallel, testing if each source is newer
138 than its corresponding target. Return a pair of lists (sources,
139 targets) where source is newer than target, according to the
140 semantics of 'newer()'."""
Greg Ward138ce651999-09-13 03:09:38 +0000141
142 if len (sources) != len (targets):
143 raise ValueError, "'sources' and 'targets' must be same length"
144
Greg Ward95526652000-03-06 03:44:32 +0000145 # build a pair of lists (sources, targets) where source is newer
146 n_sources = []
147 n_targets = []
148 for i in range (len (sources)):
149 if newer (sources[i], targets[i]):
150 n_sources.append (sources[i])
151 n_targets.append (targets[i])
152
153 return (n_sources, n_targets)
Greg Ward138ce651999-09-13 03:09:38 +0000154
155# newer_pairwise ()
156
157
Greg Ward7b7679e2000-01-09 22:48:59 +0000158def newer_group (sources, target, missing='error'):
Greg Ward138ce651999-09-13 03:09:38 +0000159 """Return true if 'target' is out-of-date with respect to any
160 file listed in 'sources'. In other words, if 'target' exists and
161 is newer than every file in 'sources', return false; otherwise
Greg Ward7b7679e2000-01-09 22:48:59 +0000162 return true. 'missing' controls what we do when a source file is
163 missing; the default ("error") is to blow up with an OSError from
164 inside 'stat()'; if it is "ignore", we silently drop any missing
165 source files; if it is "newer", any missing source files make us
166 assume that 'target' is out-of-date (this is handy in "dry-run"
167 mode: it'll make you pretend to carry out commands that wouldn't
168 work because inputs are missing, but that doesn't matter because
169 you're not actually going to run the commands)."""
Greg Ward138ce651999-09-13 03:09:38 +0000170
171 # If the target doesn't even exist, then it's definitely out-of-date.
172 if not os.path.exists (target):
173 return 1
174
175 # Otherwise we have to find out the hard way: if *any* source file
176 # is more recent than 'target', then 'target' is out-of-date and
177 # we can immediately return true. If we fall through to the end
178 # of the loop, then 'target' is up-to-date and we return false.
179 from stat import ST_MTIME
180 target_mtime = os.stat (target)[ST_MTIME]
181 for source in sources:
Greg Ward7b7679e2000-01-09 22:48:59 +0000182 if not os.path.exists (source):
183 if missing == 'error': # blow up when we stat() the file
184 pass
185 elif missing == 'ignore': # missing source dropped from
186 continue # target's dependency list
187 elif missing == 'newer': # missing source means target is
188 return 1 # out-of-date
189
Greg Ward138ce651999-09-13 03:09:38 +0000190 source_mtime = os.stat(source)[ST_MTIME]
191 if source_mtime > target_mtime:
192 return 1
193 else:
194 return 0
195
196# newer_group ()
197
198
Greg Wardf3b997a1999-10-03 20:50:41 +0000199# XXX this isn't used anywhere, and worse, it has the same name as a method
200# in Command with subtly different semantics. (This one just has one
201# source -> one dest; that one has many sources -> one dest.) Nuke it?
Greg Ward2689e3d1999-03-22 14:52:19 +0000202def make_file (src, dst, func, args,
203 verbose=0, update_message=None, noupdate_message=None):
204 """Makes 'dst' from 'src' (both filenames) by calling 'func' with
205 'args', but only if it needs to: i.e. if 'dst' does not exist or
206 'src' is newer than 'dst'."""
207
208 if newer (src, dst):
209 if verbose and update_message:
210 print update_message
211 apply (func, args)
212 else:
213 if verbose and noupdate_message:
214 print noupdate_message
215
216# make_file ()
217
218
219def _copy_file_contents (src, dst, buffer_size=16*1024):
220 """Copy the file 'src' to 'dst'; both must be filenames. Any error
221 opening either file, reading from 'src', or writing to 'dst',
222 raises DistutilsFileError. Data is read/written in chunks of
223 'buffer_size' bytes (default 16k). No attempt is made to handle
224 anything apart from regular files."""
225
226 # Stolen from shutil module in the standard library, but with
227 # custom error-handling added.
228
229 fsrc = None
230 fdst = None
231 try:
232 try:
233 fsrc = open(src, 'rb')
234 except os.error, (errno, errstr):
Greg Ward96182d72000-03-03 03:00:02 +0000235 raise DistutilsFileError, \
236 "could not open '%s': %s" % (src, errstr)
Greg Ward2689e3d1999-03-22 14:52:19 +0000237
238 try:
239 fdst = open(dst, 'wb')
240 except os.error, (errno, errstr):
Greg Ward96182d72000-03-03 03:00:02 +0000241 raise DistutilsFileError, \
242 "could not create '%s': %s" % (dst, errstr)
Greg Ward2689e3d1999-03-22 14:52:19 +0000243
244 while 1:
245 try:
246 buf = fsrc.read (buffer_size)
247 except os.error, (errno, errstr):
248 raise DistutilsFileError, \
Greg Ward96182d72000-03-03 03:00:02 +0000249 "could not read from '%s': %s" % (src, errstr)
Greg Ward2689e3d1999-03-22 14:52:19 +0000250
251 if not buf:
252 break
253
254 try:
255 fdst.write(buf)
256 except os.error, (errno, errstr):
257 raise DistutilsFileError, \
Greg Ward96182d72000-03-03 03:00:02 +0000258 "could not write to '%s': %s" % (dst, errstr)
Greg Ward2689e3d1999-03-22 14:52:19 +0000259
260 finally:
261 if fdst:
262 fdst.close()
263 if fsrc:
264 fsrc.close()
265
266# _copy_file_contents()
267
268
269def copy_file (src, dst,
270 preserve_mode=1,
271 preserve_times=1,
272 update=0,
Greg Ward32ce3292000-03-31 03:02:22 +0000273 link=None,
Greg Warde765a3b1999-04-04 02:54:20 +0000274 verbose=0,
275 dry_run=0):
Greg Ward2689e3d1999-03-22 14:52:19 +0000276
277 """Copy a file 'src' to 'dst'. If 'dst' is a directory, then 'src'
278 is copied there with the same name; otherwise, it must be a
279 filename. (If the file exists, it will be ruthlessly clobbered.)
280 If 'preserve_mode' is true (the default), the file's mode (type
281 and permission bits, or whatever is analogous on the current
282 platform) is copied. If 'preserve_times' is true (the default),
283 the last-modified and last-access times are copied as well. If
284 'update' is true, 'src' will only be copied if 'dst' does not
285 exist, or if 'dst' does exist but is older than 'src'. If
286 'verbose' is true, then a one-line summary of the copy will be
Greg Ward884df451999-05-02 21:42:05 +0000287 printed to stdout.
288
Greg Ward32ce3292000-03-31 03:02:22 +0000289 'link' allows you to make hard links (os.link) or symbolic links
290 (os.symlink) instead of copying: set it to "hard" or "sym"; if it
291 is None (the default), files are copied. Don't set 'link' on
292 systems that don't support it: 'copy_file()' doesn't check if
293 hard or symbolic linking is availalble.
294
295 Under Mac OS, uses the native file copy function in macostools;
296 on other systems, uses '_copy_file_contents()' to copy file
297 contents.
298
Greg Ward884df451999-05-02 21:42:05 +0000299 Return true if the file was copied (or would have been copied),
300 false otherwise (ie. 'update' was true and the destination is
301 up-to-date)."""
Greg Ward2689e3d1999-03-22 14:52:19 +0000302
Greg Ward32ce3292000-03-31 03:02:22 +0000303 # XXX if the destination file already exists, we clobber it if
304 # copying, but blow up if linking. Hmmm. And I don't know what
305 # macostools.copyfile() does. Should definitely be consistent, and
306 # should probably blow up if destination exists and we would be
307 # changing it (ie. it's not already a hard/soft link to src OR
308 # (not update) and (src newer than dst).
309
Greg Ward2689e3d1999-03-22 14:52:19 +0000310 from stat import *
311
312 if not os.path.isfile (src):
313 raise DistutilsFileError, \
Greg Ward32ce3292000-03-31 03:02:22 +0000314 "can't copy '%s': doesn't exist or not a regular file" % src
Greg Ward2689e3d1999-03-22 14:52:19 +0000315
316 if os.path.isdir (dst):
317 dir = dst
318 dst = os.path.join (dst, os.path.basename (src))
319 else:
320 dir = os.path.dirname (dst)
321
322 if update and not newer (src, dst):
Greg Ward884df451999-05-02 21:42:05 +0000323 if verbose:
324 print "not copying %s (output up-to-date)" % src
325 return 0
Greg Ward2689e3d1999-03-22 14:52:19 +0000326
Greg Ward32ce3292000-03-31 03:02:22 +0000327 try:
328 action = _copy_action[link]
329 except KeyError:
330 raise ValueError, \
331 "invalid value '%s' for 'link' argument" % link
Greg Ward2689e3d1999-03-22 14:52:19 +0000332 if verbose:
Greg Ward32ce3292000-03-31 03:02:22 +0000333 print "%s %s -> %s" % (action, src, dir)
Greg Ward2689e3d1999-03-22 14:52:19 +0000334
Greg Warde765a3b1999-04-04 02:54:20 +0000335 if dry_run:
Greg Ward884df451999-05-02 21:42:05 +0000336 return 1
Greg Warde765a3b1999-04-04 02:54:20 +0000337
Greg Ward911d8662000-03-07 03:34:16 +0000338 # On a Mac, use the native file copy routine
339 if os.name == 'mac':
340 import macostools
341 try:
342 macostools.copy (src, dst, 0, preserve_times)
343 except OSError, exc:
344 raise DistutilsFileError, \
345 "could not copy '%s' to '%s': %s" % (src, dst, exc[-1])
Greg Ward911d8662000-03-07 03:34:16 +0000346
Greg Ward32ce3292000-03-31 03:02:22 +0000347 # If linking (hard or symbolic), use the appropriate system call
348 # (Unix only, of course, but that's the caller's responsibility)
349 elif link == 'hard':
350 if not (os.path.exists (dst) and os.path.samefile (src, dst)):
351 os.link (src, dst)
352 elif link == 'sym':
353 if not (os.path.exists (dst) and os.path.samefile (src, dst)):
354 os.symlink (src, dst)
Greg Ward5116f901999-06-08 17:05:21 +0000355
Greg Ward32ce3292000-03-31 03:02:22 +0000356 # Otherwise (non-Mac, not linking), copy the file contents and
357 # (optionally) copy the times and mode.
358 else:
359 _copy_file_contents (src, dst)
360 if preserve_mode or preserve_times:
361 st = os.stat (src)
362
363 # According to David Ascher <da@ski.org>, utime() should be done
364 # before chmod() (at least under NT).
365 if preserve_times:
366 os.utime (dst, (st[ST_ATIME], st[ST_MTIME]))
367 if preserve_mode:
368 os.chmod (dst, S_IMODE (st[ST_MODE]))
Greg Ward2689e3d1999-03-22 14:52:19 +0000369
Greg Ward884df451999-05-02 21:42:05 +0000370 return 1
371
Greg Ward2689e3d1999-03-22 14:52:19 +0000372# copy_file ()
373
374
375def copy_tree (src, dst,
376 preserve_mode=1,
377 preserve_times=1,
378 preserve_symlinks=0,
379 update=0,
Greg Warde765a3b1999-04-04 02:54:20 +0000380 verbose=0,
381 dry_run=0):
382
Greg Ward2689e3d1999-03-22 14:52:19 +0000383 """Copy an entire directory tree 'src' to a new location 'dst'. Both
384 'src' and 'dst' must be directory names. If 'src' is not a
Greg Ward044b7c12000-03-29 03:27:45 +0000385 directory, raise DistutilsFileError. If 'dst' does not exist, it is
386 created with 'mkpath()'. The end result of the copy is that every
387 file in 'src' is copied to 'dst', and directories under 'src' are
388 recursively copied to 'dst'. Return the list of files that were
389 copied or might have been copied, using their output name. The
390 return value is unaffected by 'update' or 'dry_run': it is simply
391 the list of all files under 'src', with the names changed to be
392 under 'dst'.
Greg Ward2689e3d1999-03-22 14:52:19 +0000393
394 'preserve_mode' and 'preserve_times' are the same as for
395 'copy_file'; note that they only apply to regular files, not to
396 directories. If 'preserve_symlinks' is true, symlinks will be
397 copied as symlinks (on platforms that support them!); otherwise
398 (the default), the destination of the symlink will be copied.
399 'update' and 'verbose' are the same as for 'copy_file'."""
400
Greg Ward138ce651999-09-13 03:09:38 +0000401 if not dry_run and not os.path.isdir (src):
Greg Ward2689e3d1999-03-22 14:52:19 +0000402 raise DistutilsFileError, \
Greg Ward96182d72000-03-03 03:00:02 +0000403 "cannot copy tree '%s': not a directory" % src
Greg Ward2689e3d1999-03-22 14:52:19 +0000404 try:
405 names = os.listdir (src)
406 except os.error, (errno, errstr):
Greg Ward138ce651999-09-13 03:09:38 +0000407 if dry_run:
408 names = []
409 else:
410 raise DistutilsFileError, \
Greg Ward96182d72000-03-03 03:00:02 +0000411 "error listing files in '%s': %s" % (src, errstr)
Greg Ward2689e3d1999-03-22 14:52:19 +0000412
Greg Warde765a3b1999-04-04 02:54:20 +0000413 if not dry_run:
414 mkpath (dst, verbose=verbose)
Greg Ward2689e3d1999-03-22 14:52:19 +0000415
Greg Ward884df451999-05-02 21:42:05 +0000416 outputs = []
417
Greg Ward2689e3d1999-03-22 14:52:19 +0000418 for n in names:
419 src_name = os.path.join (src, n)
420 dst_name = os.path.join (dst, n)
421
422 if preserve_symlinks and os.path.islink (src_name):
423 link_dest = os.readlink (src_name)
Greg Warde765a3b1999-04-04 02:54:20 +0000424 if verbose:
425 print "linking %s -> %s" % (dst_name, link_dest)
426 if not dry_run:
427 os.symlink (link_dest, dst_name)
Greg Ward884df451999-05-02 21:42:05 +0000428 outputs.append (dst_name)
429
Greg Ward2689e3d1999-03-22 14:52:19 +0000430 elif os.path.isdir (src_name):
Greg Warda002edc2000-01-30 19:57:48 +0000431 outputs.extend (
Greg Ward884df451999-05-02 21:42:05 +0000432 copy_tree (src_name, dst_name,
433 preserve_mode, preserve_times, preserve_symlinks,
Greg Warda002edc2000-01-30 19:57:48 +0000434 update, verbose, dry_run))
Greg Ward2689e3d1999-03-22 14:52:19 +0000435 else:
Greg Ward044b7c12000-03-29 03:27:45 +0000436 copy_file (src_name, dst_name,
437 preserve_mode, preserve_times,
Greg Ward32ce3292000-03-31 03:02:22 +0000438 update, None, verbose, dry_run)
Greg Ward044b7c12000-03-29 03:27:45 +0000439 outputs.append (dst_name)
Greg Ward884df451999-05-02 21:42:05 +0000440
441 return outputs
Greg Ward2689e3d1999-03-22 14:52:19 +0000442
443# copy_tree ()
Greg Ward138ce651999-09-13 03:09:38 +0000444
445
Greg Wardb98fe362000-03-18 15:42:22 +0000446def remove_tree (directory, verbose=0, dry_run=0):
447 """Recursively remove an entire directory tree. Any errors are ignored
448 (apart from being reported to stdout if 'verbose' is true)."""
449
450 if verbose:
451 print "removing '%s' (and everything under it)" % directory
452 if dry_run:
453 return
454 try:
455 shutil.rmtree(directory,1)
456 except (IOError, OSError), exc:
457 if verbose:
458 if exc.filename:
459 print "error removing %s: %s (%s)" % \
460 (directory, exc.strerror, exc.filename)
461 else:
462 print "error removing %s: %s" % (directory, exc.strerror)
463
464
Greg Ward138ce651999-09-13 03:09:38 +0000465# XXX I suspect this is Unix-specific -- need porting help!
466def move_file (src, dst,
467 verbose=0,
468 dry_run=0):
469
470 """Move a file 'src' to 'dst'. If 'dst' is a directory, the file
471 will be moved into it with the same name; otherwise, 'src' is
472 just renamed to 'dst'. Return the new full name of the file.
473
474 Handles cross-device moves on Unix using
475 'copy_file()'. What about other systems???"""
476
477 from os.path import exists, isfile, isdir, basename, dirname
478
479 if verbose:
480 print "moving %s -> %s" % (src, dst)
481
482 if dry_run:
483 return dst
484
485 if not isfile (src):
486 raise DistutilsFileError, \
487 "can't move '%s': not a regular file" % src
488
489 if isdir (dst):
490 dst = os.path.join (dst, basename (src))
491 elif exists (dst):
492 raise DistutilsFileError, \
493 "can't move '%s': destination '%s' already exists" % \
494 (src, dst)
495
496 if not isdir (dirname (dst)):
497 raise DistutilsFileError, \
498 "can't move '%s': destination '%s' not a valid path" % \
499 (src, dst)
500
501 copy_it = 0
502 try:
503 os.rename (src, dst)
504 except os.error, (num, msg):
505 if num == errno.EXDEV:
506 copy_it = 1
507 else:
508 raise DistutilsFileError, \
509 "couldn't move '%s' to '%s': %s" % (src, dst, msg)
510
511 if copy_it:
512 copy_file (src, dst)
513 try:
514 os.unlink (src)
515 except os.error, (num, msg):
516 try:
517 os.unlink (dst)
518 except os.error:
519 pass
520 raise DistutilsFileError, \
521 ("couldn't move '%s' to '%s' by copy/delete: " +
522 "delete '%s' failed: %s") % \
523 (src, dst, src, msg)
524
525 return dst
526
527# move_file ()
Greg Wardac1424a1999-09-21 18:37:51 +0000528
529
530def write_file (filename, contents):
Greg Wardf3b997a1999-10-03 20:50:41 +0000531 """Create a file with the specified name and write 'contents' (a
Greg Wardac1424a1999-09-21 18:37:51 +0000532 sequence of strings without line terminators) to it."""
533
534 f = open (filename, "w")
535 for line in contents:
536 f.write (line + "\n")
537 f.close ()
Greg Ward585df892000-03-01 14:40:15 +0000538
539
540def get_platform ():
541 """Return a string (suitable for tacking onto directory names) that
542 identifies the current platform. Under Unix, identifies both the OS
543 and hardware architecture, e.g. "linux-i586", "solaris-sparc",
544 "irix-mips". For Windows and Mac OS, just returns 'sys.platform' --
545 i.e. "???" or "???"."""
546
547 if os.name == 'posix':
548 uname = os.uname()
549 OS = uname[0]
550 arch = uname[4]
551 return "%s-%s" % (string.lower (OS), string.lower (arch))
552 else:
553 return sys.platform
554
555# get_platform()
Greg Ward50919292000-03-07 03:27:08 +0000556
557
558def native_path (pathname):
559 """Return 'pathname' as a name that will work on the native
560 filesystem, i.e. split it on '/' and put it back together again
561 using the current directory separator. Needed because filenames in
562 the setup script are always supplied in Unix style, and have to be
563 converted to the local convention before we can actually use them in
564 the filesystem. Raises DistutilsValueError if 'pathname' is
565 absolute (starts with '/') or contains local directory separators
566 (unless the local separator is '/', of course)."""
567
568 if pathname[0] == '/':
569 raise DistutilsValueError, "path '%s' cannot be absolute" % pathname
570 if pathname[-1] == '/':
571 raise DistutilsValueError, "path '%s' cannot end with '/'" % pathname
Greg Ward1b4ede52000-03-22 00:22:44 +0000572 if os.sep != '/' and os.sep in pathname:
573 raise DistutilsValueError, \
574 "path '%s' cannot contain '%c' character" % \
575 (pathname, os.sep)
Greg Ward50919292000-03-07 03:27:08 +0000576
577 paths = string.split (pathname, '/')
578 return apply (os.path.join, paths)
579 else:
580 return pathname
581
582# native_path ()
Greg Ward1b4ede52000-03-22 00:22:44 +0000583
584
585def _check_environ ():
586 """Ensure that 'os.environ' has all the environment variables we
587 guarantee that users can use in config files, command-line
588 options, etc. Currently this includes:
589 HOME - user's home directory (Unix only)
590 PLAT - desription of the current platform, including hardware
591 and OS (see 'get_platform()')
592 """
593
594 if os.name == 'posix' and not os.environ.has_key('HOME'):
595 import pwd
596 os.environ['HOME'] = pwd.getpwuid (os.getuid())[5]
597
598 if not os.environ.has_key('PLAT'):
599 os.environ['PLAT'] = get_platform ()
600
601
602def subst_vars (str, local_vars):
603 """Perform shell/Perl-style variable substitution on 'string'.
604 Every occurence of '$' followed by a name, or a name enclosed in
605 braces, is considered a variable. Every variable is substituted by
606 the value found in the 'local_vars' dictionary, or in 'os.environ'
607 if it's not in 'local_vars'. 'os.environ' is first checked/
608 augmented to guarantee that it contains certain values: see
609 '_check_environ()'. Raise ValueError for any variables not found in
610 either 'local_vars' or 'os.environ'."""
611
612 _check_environ ()
613 def _subst (match, local_vars=local_vars):
614 var_name = match.group(1)
615 if local_vars.has_key (var_name):
616 return str (local_vars[var_name])
617 else:
618 return os.environ[var_name]
619
620 return re.sub (r'\$([a-zA-Z_][a-zA-Z_0-9]*)', _subst, str)
621
622# subst_vars ()
Greg Ward7c1a6d42000-03-29 02:48:40 +0000623
624
Greg Ward32ce3292000-03-31 03:02:22 +0000625def make_tarball (base_name, base_dir, compress="gzip",
626 verbose=0, dry_run=0):
Greg Ward7c1a6d42000-03-29 02:48:40 +0000627 """Create a (possibly compressed) tar file from all the files under
628 'base_dir'. 'compress' must be "gzip" (the default), "compress", or
629 None. Both "tar" and the compression utility named by 'compress'
630 must be on the default program search path, so this is probably
631 Unix-specific. The output tar file will be named 'base_dir' +
632 ".tar", possibly plus the appropriate compression extension
633 (".gz" or ".Z"). Return the output filename."""
634
635 # XXX GNU tar 1.13 has a nifty option to add a prefix directory.
636 # It's pretty new, though, so we certainly can't require it --
637 # but it would be nice to take advantage of it to skip the
638 # "create a tree of hardlinks" step! (Would also be nice to
639 # detect GNU tar to use its 'z' option and save a step.)
640
641 compress_ext = { 'gzip': ".gz",
642 'compress': ".Z" }
643
644 if compress is not None and compress not in ('gzip', 'compress'):
645 raise ValueError, \
646 "bad value for 'compress': must be None, 'gzip', or 'compress'"
647
Greg Ward32ce3292000-03-31 03:02:22 +0000648 archive_name = base_name + ".tar"
Greg Ward7c1a6d42000-03-29 02:48:40 +0000649 cmd = ["tar", "-cf", archive_name, base_dir]
650 spawn (cmd, verbose=verbose, dry_run=dry_run)
651
652 if compress:
653 spawn ([compress, archive_name], verbose=verbose, dry_run=dry_run)
654 return archive_name + compress_ext[compress]
655 else:
656 return archive_name
657
658# make_tarball ()
659
660
Greg Ward32ce3292000-03-31 03:02:22 +0000661def make_zipfile (base_name, base_dir, verbose=0, dry_run=0):
662 """Create a zip file from all the files under 'base_dir'. The
663 output zip file will be named 'base_dir' + ".zip". Uses either the
Greg Ward7c1a6d42000-03-29 02:48:40 +0000664 InfoZIP "zip" utility (if installed and found on the default search
665 path) or the "zipfile" Python module (if available). If neither
666 tool is available, raises DistutilsExecError. Returns the name
Greg Ward32ce3292000-03-31 03:02:22 +0000667 of the output zip file."""
Greg Ward7c1a6d42000-03-29 02:48:40 +0000668
669 # This initially assumed the Unix 'zip' utility -- but
670 # apparently InfoZIP's zip.exe works the same under Windows, so
671 # no changes needed!
672
Greg Ward32ce3292000-03-31 03:02:22 +0000673 zip_filename = base_name + ".zip"
Greg Ward7c1a6d42000-03-29 02:48:40 +0000674 try:
Greg Ward32ce3292000-03-31 03:02:22 +0000675 spawn (["zip", "-rq", zip_filename, base_dir],
Greg Ward7c1a6d42000-03-29 02:48:40 +0000676 verbose=verbose, dry_run=dry_run)
677 except DistutilsExecError:
678
679 # XXX really should distinguish between "couldn't find
680 # external 'zip' command" and "zip failed" -- shouldn't try
681 # again in the latter case. (I think fixing this will
682 # require some cooperation from the spawn module -- perhaps
683 # a utility function to search the path, so we can fallback
684 # on zipfile.py without the failed spawn.)
685 try:
686 import zipfile
687 except ImportError:
688 raise DistutilsExecError, \
689 ("unable to create zip file '%s': " +
690 "could neither find a standalone zip utility nor " +
691 "import the 'zipfile' module") % zip_filename
692
693 if verbose:
694 print "creating '%s' and adding '%s' to it" % \
695 (zip_filename, base_dir)
696
697 def visit (z, dirname, names):
698 for name in names:
699 path = os.path.join (dirname, name)
700 if os.path.isfile (path):
701 z.write (path, path)
702
703 if not dry_run:
704 z = zipfile.ZipFile (zip_filename, "wb",
705 compression=zipfile.ZIP_DEFLATED)
706
707 os.path.walk (base_dir, visit, z)
708 z.close()
709
710 return zip_filename
711
712# make_zipfile ()
Greg Ward32ce3292000-03-31 03:02:22 +0000713
714
715def make_archive (base_name, format,
716 root_dir=None, base_dir=None,
717 verbose=0, dry_run=0):
718
719 """Create an archive file (eg. zip or tar). 'base_name' is the name
720 of the file to create, minus any format-specific extension; 'format'
721 is the archive format: one of "zip", "tar", "ztar", or "gztar".
722 'root_dir' is a directory that will be the root directory of the
723 archive; ie. we typically chdir into 'root_dir' before creating the
724 archive. 'base_dir' is the directory where we start archiving from;
725 ie. 'base_dir' will be the common prefix of all files and
726 directories in the archive. 'root_dir' and 'base_dir' both default
727 to the current directory."""
728
729 save_cwd = os.getcwd()
730 if root_dir is not None:
731 if verbose:
732 print "changing into '%s'" % root_dir
733 base_name = os.path.abspath (base_name)
734 if not dry_run:
735 os.chdir (root_dir)
736
737 if base_dir is None:
738 base_dir = os.curdir
739
740 kwargs = { 'verbose': verbose,
741 'dry_run': dry_run }
742
743 if format == 'gztar':
744 func = make_tarball
745 kwargs['compress'] = 'gzip'
746 elif format == 'ztar':
747 func = make_tarball
748 kwargs['compress'] = 'compress'
749 elif format == 'tar':
750 func = make_tarball
751 elif format == 'zip':
752 func = make_zipfile
753
754 apply (func, (base_name, base_dir), kwargs)
755
756 if root_dir is not None:
757 if verbose:
758 print "changing back to '%s'" % save_cwd
759 os.chdir (save_cwd)
760
761# make_archive ()