24
24
import bzrlib.errors as errors
25
25
from bzrlib.errors import BzrError
26
26
from bzrlib.osutils import file_iterator, safe_unicode
27
from bzrlib.symbol_versioning import (deprecated_method,
27
from bzrlib.symbol_versioning import (deprecated_method,
29
29
from bzrlib.trace import mutter, note
30
30
import bzrlib.transactions as transactions
31
31
import bzrlib.urlutils as urlutils
144
144
"""Return location relative to branch."""
145
145
return self._transport.abspath(self._escape(file_or_path))
147
@deprecated_method(zero_eight)
148
def controlfile(self, file_or_path, mode='r'):
149
"""Open a control file for this branch.
151
There are two classes of file in a lockable directory: text
152
and binary. binary files are untranslated byte streams. Text
153
control files are stored with Unix newlines and in UTF-8, even
154
if the platform or locale defaults are different.
156
Such files are not openable in write mode : they are managed via
157
put and put_utf8 which atomically replace old versions using
161
relpath = self._escape(file_or_path)
162
# TODO: codecs.open() buffers linewise, so it was overloaded with
163
# a much larger buffer, do we need to do the same for getreader/getwriter?
165
return self.get(relpath)
167
raise BzrError("Branch.controlfile(mode='wb') is not supported, use put[_utf8]")
169
return self.get_utf8(relpath)
171
raise BzrError("Branch.controlfile(mode='w') is not supported, use put[_utf8]")
173
raise BzrError("invalid controlfile mode %r" % mode)
176
148
def get(self, relpath):
177
149
"""Get a file as a bytestream."""
194
166
:param f: A file-like or string object whose contents should be copied.
196
self._transport.put(self._escape(path), file, mode=self._file_mode)
168
self._transport.put_file(self._escape(path), file, mode=self._file_mode)
171
def put_bytes(self, path, a_string):
172
"""Write a string of bytes.
174
:param path: The path to put the bytes, relative to the transport root.
175
:param string: A string object, whose exact bytes are to be copied.
177
self._transport.put_bytes(self._escape(path), a_string,
178
mode=self._file_mode)
198
180
@needs_write_lock
199
181
def put_utf8(self, path, a_string):
200
182
"""Write a string, encoding as utf-8.
202
184
:param path: The path to put the string, relative to the transport root.
203
:param string: A file-like or string object whose contents should be copied.
185
:param string: A string or unicode object whose contents should be copied.
205
187
# IterableFile would not be needed if Transport.put took iterables
206
188
# instead of files. ADHB 2005-12-25
210
192
# these are valuable files which should have exact contents.
211
193
if not isinstance(a_string, basestring):
212
194
raise errors.BzrBadParameterNotString(a_string)
213
self.put(path, StringIO(a_string.encode('utf-8')))
215
def lock_write(self):
195
self.put_bytes(path, a_string.encode('utf-8'))
197
def leave_in_place(self):
198
"""Set this LockableFiles to not clear the physical lock on unlock."""
199
self._lock.leave_in_place()
201
def dont_leave_in_place(self):
202
"""Set this LockableFiles to clear the physical lock on unlock."""
203
self._lock.dont_leave_in_place()
205
def lock_write(self, token=None):
206
"""Lock this group of files for writing.
208
:param token: if this is already locked, then lock_write will fail
209
unless the token matches the existing lock.
210
:returns: a token if this instance supports tokens, otherwise None.
211
:raises TokenLockingNotSupported: when a token is given but this
212
instance doesn't support using token locks.
213
:raises MismatchedToken: if the specified token doesn't match the token
214
of the existing lock.
216
A token should be passed in if you know that you have locked the object
217
some other way, and need to synchronise this object's state with that
216
220
# mutter("lock write: %s (%s)", self, self._lock_count)
217
221
# TODO: Upgrade locking to support using a Transport,
218
222
# and potentially a remote locking protocol
219
223
if self._lock_mode:
220
224
if self._lock_mode != 'w' or not self.get_transaction().writeable():
221
225
raise errors.ReadOnlyError(self)
226
self._lock.validate_token(token)
222
227
self._lock_count += 1
228
return self._token_from_lock
224
self._lock.lock_write()
230
token_from_lock = self._lock.lock_write(token=token)
225
231
#note('write locking %s', self)
226
232
#traceback.print_stack()
227
233
self._lock_mode = 'w'
228
234
self._lock_count = 1
229
235
self._set_transaction(transactions.WriteTransaction())
236
self._token_from_lock = token_from_lock
237
return token_from_lock
231
239
def lock_read(self):
232
240
# mutter("lock read: %s (%s)", self, self._lock_count)
323
331
def break_lock(self):
324
332
raise NotImplementedError(self.break_lock)
326
def lock_write(self):
334
def leave_in_place(self):
335
raise NotImplementedError(self.leave_in_place)
337
def dont_leave_in_place(self):
338
raise NotImplementedError(self.dont_leave_in_place)
340
def lock_write(self, token=None):
341
if token is not None:
342
raise errors.TokenLockingNotSupported(self)
327
343
self._lock = self._transport.lock_write(self._escaped_name)
329
345
def lock_read(self):
339
355
def create(self, mode=None):
340
356
"""Create lock mechanism"""
341
357
# for old-style locks, create the file now
342
self._transport.put(self._escaped_name, StringIO(),
358
self._transport.put_bytes(self._escaped_name, '',
343
359
mode=self._file_modebits)
361
def validate_token(self, token):
362
if token is not None:
363
raise errors.TokenLockingNotSupported(self)