14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
from cStringIO import StringIO
20
21
from bzrlib.decorators import *
21
22
import bzrlib.errors as errors
22
23
from bzrlib.errors import LockError, ReadOnlyError
23
24
from bzrlib.osutils import file_iterator, safe_unicode
25
from bzrlib.symbol_versioning import *
26
from bzrlib.symbol_versioning import deprecated_method, zero_seven
24
27
from bzrlib.trace import mutter
25
28
import bzrlib.transactions as transactions
97
100
"""Return location relative to branch."""
98
101
return self._transport.abspath(self._escape(file_or_path))
103
@deprecated_method(zero_seven)
100
104
def controlfile(self, file_or_path, mode='r'):
101
105
"""Open a control file for this branch.
109
113
put and put_utf8 which atomically replace old versions using
114
117
relpath = self._escape(file_or_path)
115
118
#TODO: codecs.open() buffers linewise, so it was overloaded with
116
119
# a much larger buffer, do we need to do the same for getreader/getwriter?
118
return self._transport.get(relpath)
121
return self.get(relpath)
119
122
elif mode == 'wb':
120
123
raise BzrError("Branch.controlfile(mode='wb') is not supported, use put[_utf8]")
121
124
elif mode == 'r':
122
# XXX: Do we really want errors='replace'? Perhaps it should be
123
# an error, or at least reported, if there's incorrectly-encoded
124
# data inside a file.
125
# <https://launchpad.net/products/bzr/+bug/3823>
126
return codecs.getreader('utf-8')(self._transport.get(relpath), errors='replace')
125
return self.get_utf8(relpath)
127
126
elif mode == 'w':
128
127
raise BzrError("Branch.controlfile(mode='w') is not supported, use put[_utf8]")
130
129
raise BzrError("invalid controlfile mode %r" % mode)
132
def get(self, relpath):
133
"""Get a file as a bytestream."""
134
relpath = self._escape(relpath)
135
return self._transport.get(relpath)
138
def get_utf8(self, relpath):
139
"""Get a file as a unicode stream."""
140
relpath = self._escape(relpath)
141
# DO NOT introduce an errors=replace here.
142
return codecs.getreader('utf-8')(self._transport.get(relpath))
132
144
@needs_write_lock
133
145
def put(self, path, file):
140
152
self._transport.put(self._escape(path), file, mode=self._file_mode)
142
154
@needs_write_lock
143
def put_utf8(self, path, file, mode=None):
144
"""Write a file, encoding as utf-8.
155
def put_utf8(self, path, a_string):
156
"""Write a string, encoding as utf-8.
146
:param path: The path to put the file, relative to the .bzr control
148
:param f: A file-like or string object whose contents should be copied.
158
:param path: The path to put the string, relative to the transport root.
159
:param string: A file-like or string object whose contents should be copied.
151
from iterablefile import IterableFile
153
if hasattr(file, 'read'):
154
iterator = file_iterator(file)
157
161
# IterableFile would not be needed if Transport.put took iterables
158
162
# instead of files. ADHB 2005-12-25
159
163
# RBC 20060103 surely its not needed anyway, with codecs transcode
161
165
# JAM 20060103 We definitely don't want encode(..., 'replace')
162
166
# these are valuable files which should have exact contents.
163
encoded_file = IterableFile(b.encode('utf-8') for b in
165
self.put(path, encoded_file)
167
if not isinstance(a_string, basestring):
168
raise errors.BzrBadParameterNotString(a_string)
169
self.put(path, StringIO(a_string.encode('utf-8')))
167
171
def lock_write(self):
168
172
mutter("lock write: %s (%s)", self, self._lock_count)