blob: 9a299dfd8395dd2a86085b3e4fd584f12e8cdfca [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
Greg Ward884df451999-05-02 21:42:05 +0000167 printed to stdout.
168
169 Return true if the file was copied (or would have been copied),
170 false otherwise (ie. 'update' was true and the destination is
171 up-to-date)."""
Greg Ward2689e3d1999-03-22 14:52:19 +0000172
173 # XXX doesn't copy Mac-specific metadata
174
Greg Ward2689e3d1999-03-22 14:52:19 +0000175 from stat import *
176
177 if not os.path.isfile (src):
178 raise DistutilsFileError, \
179 "can't copy %s:not a regular file" % src
180
181 if os.path.isdir (dst):
182 dir = dst
183 dst = os.path.join (dst, os.path.basename (src))
184 else:
185 dir = os.path.dirname (dst)
186
187 if update and not newer (src, dst):
Greg Ward884df451999-05-02 21:42:05 +0000188 if verbose:
189 print "not copying %s (output up-to-date)" % src
190 return 0
Greg Ward2689e3d1999-03-22 14:52:19 +0000191
192 if verbose:
193 print "copying %s -> %s" % (src, dir)
194
Greg Warde765a3b1999-04-04 02:54:20 +0000195 if dry_run:
Greg Ward884df451999-05-02 21:42:05 +0000196 return 1
Greg Warde765a3b1999-04-04 02:54:20 +0000197
198 _copy_file_contents (src, dst)
Greg Ward2689e3d1999-03-22 14:52:19 +0000199 if preserve_mode or preserve_times:
200 st = os.stat (src)
Greg Ward5116f901999-06-08 17:05:21 +0000201
202 # According to David Ascher <da@ski.org>, utime() should be done
203 # before chmod() (at least under NT).
Greg Ward2689e3d1999-03-22 14:52:19 +0000204 if preserve_times:
205 os.utime (dst, (st[ST_ATIME], st[ST_MTIME]))
Greg Ward5116f901999-06-08 17:05:21 +0000206 if preserve_mode:
207 os.chmod (dst, S_IMODE (st[ST_MODE]))
Greg Ward2689e3d1999-03-22 14:52:19 +0000208
Greg Ward884df451999-05-02 21:42:05 +0000209 return 1
210
Greg Ward2689e3d1999-03-22 14:52:19 +0000211# copy_file ()
212
213
214def copy_tree (src, dst,
215 preserve_mode=1,
216 preserve_times=1,
217 preserve_symlinks=0,
218 update=0,
Greg Warde765a3b1999-04-04 02:54:20 +0000219 verbose=0,
220 dry_run=0):
221
Greg Ward2689e3d1999-03-22 14:52:19 +0000222
223 """Copy an entire directory tree 'src' to a new location 'dst'. Both
224 'src' and 'dst' must be directory names. If 'src' is not a
225 directory, raise DistutilsFileError. If 'dst' does not exist, it
Greg Ward884df451999-05-02 21:42:05 +0000226 is created with 'mkpath'. The end result of the copy is that
Greg Ward2689e3d1999-03-22 14:52:19 +0000227 every file in 'src' is copied to 'dst', and directories under
Greg Ward884df451999-05-02 21:42:05 +0000228 'src' are recursively copied to 'dst'. Return the list of files
229 copied (under their output names) -- note that if 'update' is true,
230 this might be less than the list of files considered. Return
231 value is not affected by 'dry_run'.
Greg Ward2689e3d1999-03-22 14:52:19 +0000232
233 'preserve_mode' and 'preserve_times' are the same as for
234 'copy_file'; note that they only apply to regular files, not to
235 directories. If 'preserve_symlinks' is true, symlinks will be
236 copied as symlinks (on platforms that support them!); otherwise
237 (the default), the destination of the symlink will be copied.
238 'update' and 'verbose' are the same as for 'copy_file'."""
239
240 if not os.path.isdir (src):
241 raise DistutilsFileError, \
242 "cannot copy tree %s: not a directory" % src
243 try:
244 names = os.listdir (src)
245 except os.error, (errno, errstr):
246 raise DistutilsFileError, \
247 "error listing files in %s: %s" % (src, errstr)
248
Greg Warde765a3b1999-04-04 02:54:20 +0000249 if not dry_run:
250 mkpath (dst, verbose=verbose)
Greg Ward2689e3d1999-03-22 14:52:19 +0000251
Greg Ward884df451999-05-02 21:42:05 +0000252 outputs = []
253
Greg Ward2689e3d1999-03-22 14:52:19 +0000254 for n in names:
255 src_name = os.path.join (src, n)
256 dst_name = os.path.join (dst, n)
257
258 if preserve_symlinks and os.path.islink (src_name):
259 link_dest = os.readlink (src_name)
Greg Warde765a3b1999-04-04 02:54:20 +0000260 if verbose:
261 print "linking %s -> %s" % (dst_name, link_dest)
262 if not dry_run:
263 os.symlink (link_dest, dst_name)
Greg Ward884df451999-05-02 21:42:05 +0000264 outputs.append (dst_name)
265
Greg Ward2689e3d1999-03-22 14:52:19 +0000266 elif os.path.isdir (src_name):
Greg Ward884df451999-05-02 21:42:05 +0000267 outputs[-1:] = \
268 copy_tree (src_name, dst_name,
269 preserve_mode, preserve_times, preserve_symlinks,
270 update, verbose, dry_run)
Greg Ward2689e3d1999-03-22 14:52:19 +0000271 else:
Greg Ward884df451999-05-02 21:42:05 +0000272 if (copy_file (src_name, dst_name,
273 preserve_mode, preserve_times,
274 update, verbose, dry_run)):
275 outputs.append (dst_name)
276
277 return outputs
Greg Ward2689e3d1999-03-22 14:52:19 +0000278
279# copy_tree ()