15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
from cStringIO import StringIO
19
from bzrlib.lazy_import import lazy_import
20
lazy_import(globals(), """
32
from bzrlib.decorators import (
36
from bzrlib.symbol_versioning import (
22
from bzrlib.decorators import (needs_read_lock,
24
import bzrlib.errors as errors
25
from bzrlib.errors import BzrError
26
from bzrlib.osutils import file_iterator, safe_unicode
27
from bzrlib.symbol_versioning import (deprecated_method,
29
from bzrlib.trace import mutter, note
30
import bzrlib.transactions as transactions
31
import bzrlib.urlutils as urlutils
42
34
# XXX: The tracking here of lock counts and whether the lock is held is
123
118
self._lock.break_lock()
125
120
def _escape(self, file_or_path):
126
"""DEPRECATED: Do not use outside this class"""
127
121
if not isinstance(file_or_path, basestring):
128
122
file_or_path = '/'.join(file_or_path)
129
123
if file_or_path == '':
131
return urlutils.escape(osutils.safe_unicode(file_or_path))
125
return urlutils.escape(safe_unicode(file_or_path))
133
127
def _find_modes(self):
134
"""Determine the appropriate modes for files and directories.
136
:deprecated: Replaced by BzrDir._find_modes.
128
"""Determine the appropriate modes for files and directories."""
139
130
st = self._transport.stat('.')
140
131
except errors.TransportNotPossible:
141
132
self._dir_mode = 0755
142
133
self._file_mode = 0644
144
# Check the directory mode, but also make sure the created
145
# directories and files are read-write for this user. This is
146
# mostly a workaround for filesystems which lie about being able to
147
# write to a directory (cygwin & win32)
148
self._dir_mode = (st.st_mode & 07777) | 00700
135
self._dir_mode = st.st_mode & 07777
149
136
# Remove the sticky and execute bits for files
150
137
self._file_mode = self._dir_mode & ~07111
138
if not self._set_dir_mode:
139
self._dir_mode = None
140
if not self._set_file_mode:
141
self._file_mode = None
152
@deprecated_method(deprecated_in((1, 6, 0)))
153
143
def controlfilename(self, file_or_path):
154
"""Return location relative to branch.
156
:deprecated: Use Transport methods instead.
144
"""Return location relative to branch."""
158
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)
161
@deprecated_method(deprecated_in((1, 5, 0)))
162
176
def get(self, relpath):
163
"""Get a file as a bytestream.
165
:deprecated: Use a Transport instead of LockableFiles.
177
"""Get a file as a bytestream."""
167
178
relpath = self._escape(relpath)
168
179
return self._transport.get(relpath)
171
@deprecated_method(deprecated_in((1, 5, 0)))
172
182
def get_utf8(self, relpath):
173
"""Get a file as a unicode stream.
175
:deprecated: Use a Transport instead of LockableFiles.
183
"""Get a file as a unicode stream."""
177
184
relpath = self._escape(relpath)
178
185
# DO NOT introduce an errors=replace here.
179
186
return codecs.getreader('utf-8')(self._transport.get(relpath))
181
188
@needs_write_lock
182
@deprecated_method(deprecated_in((1, 6, 0)))
183
189
def put(self, path, file):
186
192
:param path: The path to put the file, relative to the .bzr control
188
:param file: A file-like or string object whose contents should be copied.
190
:deprecated: Use Transport methods instead.
194
:param f: A file-like or string object whose contents should be copied.
192
196
self._transport.put_file(self._escape(path), file, mode=self._file_mode)
194
198
@needs_write_lock
195
@deprecated_method(deprecated_in((1, 6, 0)))
196
def put_bytes(self, path, a_string):
197
"""Write a string of bytes.
199
:param path: The path to put the bytes, relative to the transport root.
200
:param a_string: A string object, whose exact bytes are to be copied.
202
:deprecated: Use Transport methods instead.
204
self._transport.put_bytes(self._escape(path), a_string,
205
mode=self._file_mode)
208
@deprecated_method(deprecated_in((1, 6, 0)))
209
199
def put_utf8(self, path, a_string):
210
200
"""Write a string, encoding as utf-8.
212
202
:param path: The path to put the string, relative to the transport root.
213
:param string: A string or unicode object whose contents should be copied.
215
:deprecated: Use Transport methods instead.
203
:param string: A file-like or string object whose contents should be copied.
217
205
# IterableFile would not be needed if Transport.put took iterables
218
206
# instead of files. ADHB 2005-12-25
222
210
# these are valuable files which should have exact contents.
223
211
if not isinstance(a_string, basestring):
224
212
raise errors.BzrBadParameterNotString(a_string)
225
self.put_bytes(path, a_string.encode('utf-8'))
227
def leave_in_place(self):
228
"""Set this LockableFiles to not clear the physical lock on unlock."""
229
self._lock.leave_in_place()
231
def dont_leave_in_place(self):
232
"""Set this LockableFiles to clear the physical lock on unlock."""
233
self._lock.dont_leave_in_place()
235
def lock_write(self, token=None):
236
"""Lock this group of files for writing.
238
:param token: if this is already locked, then lock_write will fail
239
unless the token matches the existing lock.
240
:returns: a token if this instance supports tokens, otherwise None.
241
:raises TokenLockingNotSupported: when a token is given but this
242
instance doesn't support using token locks.
243
:raises MismatchedToken: if the specified token doesn't match the token
244
of the existing lock.
246
A token should be passed in if you know that you have locked the object
247
some other way, and need to synchronise this object's state with that
213
self.put(path, StringIO(a_string.encode('utf-8')))
215
def lock_write(self):
216
# mutter("lock write: %s (%s)", self, self._lock_count)
250
217
# TODO: Upgrade locking to support using a Transport,
251
218
# and potentially a remote locking protocol
252
219
if self._lock_mode:
253
220
if self._lock_mode != 'w' or not self.get_transaction().writeable():
254
221
raise errors.ReadOnlyError(self)
255
self._lock.validate_token(token)
256
222
self._lock_count += 1
257
return self._token_from_lock
259
token_from_lock = self._lock.lock_write(token=token)
224
self._lock.lock_write()
225
#note('write locking %s', self)
260
226
#traceback.print_stack()
261
227
self._lock_mode = 'w'
262
228
self._lock_count = 1
263
229
self._set_transaction(transactions.WriteTransaction())
264
self._token_from_lock = token_from_lock
265
return token_from_lock
267
231
def lock_read(self):
232
# mutter("lock read: %s (%s)", self, self._lock_count)
268
233
if self._lock_mode:
269
if self._lock_mode not in ('r', 'w'):
270
raise ValueError("invalid lock mode %r" % (self._lock_mode,))
234
assert self._lock_mode in ('r', 'w'), \
235
"invalid lock mode %r" % self._lock_mode
271
236
self._lock_count += 1
273
238
self._lock.lock_read()
239
#note('read locking %s', self)
274
240
#traceback.print_stack()
275
241
self._lock_mode = 'r'
276
242
self._lock_count = 1