comparison env/lib/python3.9/site-packages/setuptools/_distutils/file_util.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 """distutils.file_util
2
3 Utility functions for operating on single files.
4 """
5
6 import os
7 from distutils.errors import DistutilsFileError
8 from distutils import log
9
10 # for generating verbose output in 'copy_file()'
11 _copy_action = { None: 'copying',
12 'hard': 'hard linking',
13 'sym': 'symbolically linking' }
14
15
16 def _copy_file_contents(src, dst, buffer_size=16*1024):
17 """Copy the file 'src' to 'dst'; both must be filenames. Any error
18 opening either file, reading from 'src', or writing to 'dst', raises
19 DistutilsFileError. Data is read/written in chunks of 'buffer_size'
20 bytes (default 16k). No attempt is made to handle anything apart from
21 regular files.
22 """
23 # Stolen from shutil module in the standard library, but with
24 # custom error-handling added.
25 fsrc = None
26 fdst = None
27 try:
28 try:
29 fsrc = open(src, 'rb')
30 except OSError as e:
31 raise DistutilsFileError("could not open '%s': %s" % (src, e.strerror))
32
33 if os.path.exists(dst):
34 try:
35 os.unlink(dst)
36 except OSError as e:
37 raise DistutilsFileError(
38 "could not delete '%s': %s" % (dst, e.strerror))
39
40 try:
41 fdst = open(dst, 'wb')
42 except OSError as e:
43 raise DistutilsFileError(
44 "could not create '%s': %s" % (dst, e.strerror))
45
46 while True:
47 try:
48 buf = fsrc.read(buffer_size)
49 except OSError as e:
50 raise DistutilsFileError(
51 "could not read from '%s': %s" % (src, e.strerror))
52
53 if not buf:
54 break
55
56 try:
57 fdst.write(buf)
58 except OSError as e:
59 raise DistutilsFileError(
60 "could not write to '%s': %s" % (dst, e.strerror))
61 finally:
62 if fdst:
63 fdst.close()
64 if fsrc:
65 fsrc.close()
66
67 def copy_file(src, dst, preserve_mode=1, preserve_times=1, update=0,
68 link=None, verbose=1, dry_run=0):
69 """Copy a file 'src' to 'dst'. If 'dst' is a directory, then 'src' is
70 copied there with the same name; otherwise, it must be a filename. (If
71 the file exists, it will be ruthlessly clobbered.) If 'preserve_mode'
72 is true (the default), the file's mode (type and permission bits, or
73 whatever is analogous on the current platform) is copied. If
74 'preserve_times' is true (the default), the last-modified and
75 last-access times are copied as well. If 'update' is true, 'src' will
76 only be copied if 'dst' does not exist, or if 'dst' does exist but is
77 older than 'src'.
78
79 'link' allows you to make hard links (os.link) or symbolic links
80 (os.symlink) instead of copying: set it to "hard" or "sym"; if it is
81 None (the default), files are copied. Don't set 'link' on systems that
82 don't support it: 'copy_file()' doesn't check if hard or symbolic
83 linking is available. If hardlink fails, falls back to
84 _copy_file_contents().
85
86 Under Mac OS, uses the native file copy function in macostools; on
87 other systems, uses '_copy_file_contents()' to copy file contents.
88
89 Return a tuple (dest_name, copied): 'dest_name' is the actual name of
90 the output file, and 'copied' is true if the file was copied (or would
91 have been copied, if 'dry_run' true).
92 """
93 # XXX if the destination file already exists, we clobber it if
94 # copying, but blow up if linking. Hmmm. And I don't know what
95 # macostools.copyfile() does. Should definitely be consistent, and
96 # should probably blow up if destination exists and we would be
97 # changing it (ie. it's not already a hard/soft link to src OR
98 # (not update) and (src newer than dst).
99
100 from distutils.dep_util import newer
101 from stat import ST_ATIME, ST_MTIME, ST_MODE, S_IMODE
102
103 if not os.path.isfile(src):
104 raise DistutilsFileError(
105 "can't copy '%s': doesn't exist or not a regular file" % src)
106
107 if os.path.isdir(dst):
108 dir = dst
109 dst = os.path.join(dst, os.path.basename(src))
110 else:
111 dir = os.path.dirname(dst)
112
113 if update and not newer(src, dst):
114 if verbose >= 1:
115 log.debug("not copying %s (output up-to-date)", src)
116 return (dst, 0)
117
118 try:
119 action = _copy_action[link]
120 except KeyError:
121 raise ValueError("invalid value '%s' for 'link' argument" % link)
122
123 if verbose >= 1:
124 if os.path.basename(dst) == os.path.basename(src):
125 log.info("%s %s -> %s", action, src, dir)
126 else:
127 log.info("%s %s -> %s", action, src, dst)
128
129 if dry_run:
130 return (dst, 1)
131
132 # If linking (hard or symbolic), use the appropriate system call
133 # (Unix only, of course, but that's the caller's responsibility)
134 elif link == 'hard':
135 if not (os.path.exists(dst) and os.path.samefile(src, dst)):
136 try:
137 os.link(src, dst)
138 return (dst, 1)
139 except OSError:
140 # If hard linking fails, fall back on copying file
141 # (some special filesystems don't support hard linking
142 # even under Unix, see issue #8876).
143 pass
144 elif link == 'sym':
145 if not (os.path.exists(dst) and os.path.samefile(src, dst)):
146 os.symlink(src, dst)
147 return (dst, 1)
148
149 # Otherwise (non-Mac, not linking), copy the file contents and
150 # (optionally) copy the times and mode.
151 _copy_file_contents(src, dst)
152 if preserve_mode or preserve_times:
153 st = os.stat(src)
154
155 # According to David Ascher <da@ski.org>, utime() should be done
156 # before chmod() (at least under NT).
157 if preserve_times:
158 os.utime(dst, (st[ST_ATIME], st[ST_MTIME]))
159 if preserve_mode:
160 os.chmod(dst, S_IMODE(st[ST_MODE]))
161
162 return (dst, 1)
163
164
165 # XXX I suspect this is Unix-specific -- need porting help!
166 def move_file (src, dst,
167 verbose=1,
168 dry_run=0):
169
170 """Move a file 'src' to 'dst'. If 'dst' is a directory, the file will
171 be moved into it with the same name; otherwise, 'src' is just renamed
172 to 'dst'. Return the new full name of the file.
173
174 Handles cross-device moves on Unix using 'copy_file()'. What about
175 other systems???
176 """
177 from os.path import exists, isfile, isdir, basename, dirname
178 import errno
179
180 if verbose >= 1:
181 log.info("moving %s -> %s", src, dst)
182
183 if dry_run:
184 return dst
185
186 if not isfile(src):
187 raise DistutilsFileError("can't move '%s': not a regular file" % src)
188
189 if isdir(dst):
190 dst = os.path.join(dst, basename(src))
191 elif exists(dst):
192 raise DistutilsFileError(
193 "can't move '%s': destination '%s' already exists" %
194 (src, dst))
195
196 if not isdir(dirname(dst)):
197 raise DistutilsFileError(
198 "can't move '%s': destination '%s' not a valid path" %
199 (src, dst))
200
201 copy_it = False
202 try:
203 os.rename(src, dst)
204 except OSError as e:
205 (num, msg) = e.args
206 if num == errno.EXDEV:
207 copy_it = True
208 else:
209 raise DistutilsFileError(
210 "couldn't move '%s' to '%s': %s" % (src, dst, msg))
211
212 if copy_it:
213 copy_file(src, dst, verbose=verbose)
214 try:
215 os.unlink(src)
216 except OSError as e:
217 (num, msg) = e.args
218 try:
219 os.unlink(dst)
220 except OSError:
221 pass
222 raise DistutilsFileError(
223 "couldn't move '%s' to '%s' by copy/delete: "
224 "delete '%s' failed: %s"
225 % (src, dst, src, msg))
226 return dst
227
228
229 def write_file (filename, contents):
230 """Create a file with the specified name and write 'contents' (a
231 sequence of strings without line terminators) to it.
232 """
233 f = open(filename, "w")
234 try:
235 for line in contents:
236 f.write(line + "\n")
237 finally:
238 f.close()