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