23
from stat import ST_MODE, S_ISDIR, ST_SIZE, S_IMODE
26
from bzrlib.lazy_import import lazy_import
27
lazy_import(globals(), """
25
from stat import ST_MODE, S_ISDIR, ST_SIZE
28
from bzrlib.osutils import (abspath, realpath, normpath, pathjoin, rename,
29
check_legal_path, rmtree)
30
from bzrlib.symbol_versioning import warn
37
31
from bzrlib.trace import mutter
40
32
from bzrlib.transport import Transport, Server
43
_append_flags = os.O_CREAT | os.O_APPEND | os.O_WRONLY | osutils.O_BINARY
44
_put_non_atomic_flags = os.O_CREAT | os.O_TRUNC | os.O_WRONLY | osutils.O_BINARY
33
import bzrlib.urlutils as urlutils
47
36
class LocalTransport(Transport):
137
125
except (IOError, OSError),e:
138
126
self._translate_error(e, path)
140
def put_file(self, relpath, f, mode=None):
141
"""Copy the file-like object into the location.
128
def put(self, relpath, f, mode=None):
129
"""Copy the file-like or string object into the location.
143
131
:param relpath: Location to put the contents, relative to base.
144
:param f: File-like object.
145
:param mode: The mode for the newly created file,
146
None means just use the default
132
:param f: File-like or string object.
134
from bzrlib.atomicfile import AtomicFile
151
138
path = self._abspath(relpath)
152
osutils.check_legal_path(path)
153
fp = atomicfile.AtomicFile(path, 'wb', new_mode=mode)
139
check_legal_path(path)
140
fp = AtomicFile(path, 'wb', new_mode=mode)
154
141
except (IOError, OSError),e:
155
142
self._translate_error(e, path)
162
def put_bytes(self, relpath, bytes, mode=None):
163
"""Copy the string into the location.
165
:param relpath: Location to put the contents, relative to base.
171
path = self._abspath(relpath)
172
osutils.check_legal_path(path)
173
fp = atomicfile.AtomicFile(path, 'wb', new_mode=mode)
174
except (IOError, OSError),e:
175
self._translate_error(e, path)
182
def _put_non_atomic_helper(self, relpath, writer,
184
create_parent_dir=False,
186
"""Common functionality information for the put_*_non_atomic.
188
This tracks all the create_parent_dir stuff.
190
:param relpath: the path we are putting to.
191
:param writer: A function that takes an os level file descriptor
192
and writes whatever data it needs to write there.
193
:param mode: The final file mode.
194
:param create_parent_dir: Should we be creating the parent directory
197
abspath = self._abspath(relpath)
199
# os.open() will automatically use the umask
204
fd = os.open(abspath, _put_non_atomic_flags, local_mode)
205
except (IOError, OSError),e:
206
# We couldn't create the file, maybe we need to create
207
# the parent directory, and try again
208
if (not create_parent_dir
209
or e.errno not in (errno.ENOENT,errno.ENOTDIR)):
210
self._translate_error(e, relpath)
211
parent_dir = os.path.dirname(abspath)
213
self._translate_error(e, relpath)
214
self._mkdir(parent_dir, mode=dir_mode)
215
# We created the parent directory, lets try to open the
218
fd = os.open(abspath, _put_non_atomic_flags, local_mode)
219
except (IOError, OSError), e:
220
self._translate_error(e, relpath)
223
if mode is not None and mode != S_IMODE(st.st_mode):
224
# Because of umask, we may still need to chmod the file.
225
# But in the general case, we won't have to
226
os.chmod(abspath, mode)
231
def put_file_non_atomic(self, relpath, f, mode=None,
232
create_parent_dir=False,
234
"""Copy the file-like object into the target location.
236
This function is not strictly safe to use. It is only meant to
237
be used when you already know that the target does not exist.
238
It is not safe, because it will open and truncate the remote
239
file. So there may be a time when the file has invalid contents.
241
:param relpath: The remote location to put the contents.
242
:param f: File-like object.
243
:param mode: Possible access permissions for new file.
244
None means do not set remote permissions.
245
:param create_parent_dir: If we cannot create the target file because
246
the parent directory does not exist, go ahead and
247
create it, and then try again.
250
self._pump_to_fd(f, fd)
251
self._put_non_atomic_helper(relpath, writer, mode=mode,
252
create_parent_dir=create_parent_dir,
255
def put_bytes_non_atomic(self, relpath, bytes, mode=None,
256
create_parent_dir=False, dir_mode=None):
259
self._put_non_atomic_helper(relpath, writer, mode=mode,
260
create_parent_dir=create_parent_dir,
263
149
def iter_files_recursive(self):
264
150
"""Iter the relative paths of files in the transports sub-tree."""
265
151
queue = list(self.list_dir(u'.'))
275
def _mkdir(self, abspath, mode=None):
276
"""Create a real directory, filtering through mode"""
278
# os.mkdir() will filter through umask
283
os.mkdir(abspath, local_mode)
285
# It is probably faster to just do the chmod, rather than
286
# doing a stat, and then trying to compare
287
os.chmod(abspath, mode)
288
except (IOError, OSError),e:
289
self._translate_error(e, abspath)
291
161
def mkdir(self, relpath, mode=None):
292
162
"""Create a directory at the given path."""
293
self._mkdir(self._abspath(relpath), mode=mode)
295
def _get_append_file(self, relpath, mode=None):
296
"""Call os.open() for the given relpath"""
297
file_abspath = self._abspath(relpath)
299
# os.open() will automatically use the umask
304
return file_abspath, os.open(file_abspath, _append_flags, local_mode)
165
path = self._abspath(relpath)
305
169
except (IOError, OSError),e:
306
self._translate_error(e, relpath)
308
def _check_mode_and_size(self, file_abspath, fd, mode=None):
309
"""Check the mode of the file, and return the current size"""
311
if mode is not None and mode != S_IMODE(st.st_mode):
312
# Because of umask, we may still need to chmod the file.
313
# But in the general case, we won't have to
314
os.chmod(file_abspath, mode)
317
def append_file(self, relpath, f, mode=None):
170
self._translate_error(e, path)
172
def append(self, relpath, f, mode=None):
318
173
"""Append the text in the file-like object into the final location."""
319
file_abspath, fd = self._get_append_file(relpath, mode=mode)
321
result = self._check_mode_and_size(file_abspath, fd, mode=mode)
322
self._pump_to_fd(f, fd)
327
def append_bytes(self, relpath, bytes, mode=None):
328
"""Append the text in the string into the final location."""
329
file_abspath, fd = self._get_append_file(relpath, mode=mode)
331
result = self._check_mode_and_size(file_abspath, fd, mode=mode)
337
def _pump_to_fd(self, fromfile, to_fd):
338
"""Copy contents of one file to another."""
341
b = fromfile.read(BUFSIZE)
174
abspath = self._abspath(relpath)
178
fp = open(abspath, 'ab')
179
# FIXME should we really be chmodding every time ? RBC 20060523
181
os.chmod(abspath, mode)
182
except (IOError, OSError),e:
183
self._translate_error(e, relpath)
184
# win32 workaround (tell on an unwritten file returns 0)
346
193
def copy(self, rel_from, rel_to):
347
194
"""Copy the item at rel_from to the location at rel_to"""
323
class LocalRelpathServer(Server):
324
"""A pretend server for local transports, using relpaths."""
327
"""See Transport.Server.get_url."""
331
class LocalAbspathServer(Server):
332
"""A pretend server for local transports, using absolute paths."""
335
"""See Transport.Server.get_url."""
336
return os.path.abspath("")
477
339
class LocalURLServer(Server):
478
"""A pretend server for local transports, using file:// urls.
480
Of course no actual server is required to access the local filesystem, so
481
this just exists to tell the test code how to get to it.
340
"""A pretend server for local transports, using file:// urls."""
484
342
def get_url(self):
485
343
"""See Transport.Server.get_url."""