Rev 5753: Merge the 2.3 branch changes up to 2.4. The final changes are in http://bazaar.launchpad.net/~jameinel/bzr/2.4-transform-cache-sha-740932
John Arbash Meinel
john at arbash-meinel.com
Mon Apr 4 13:37:47 UTC 2011
At http://bazaar.launchpad.net/~jameinel/bzr/2.4-transform-cache-sha-740932
------------------------------------------------------------
revno: 5753 [merge]
revision-id: john at arbash-meinel.com-20110404133725-5poi07a3wk5re7hm
parent: pqm at pqm.ubuntu.com-20110402231100-l6p99hxfe6722vir
parent: john at arbash-meinel.com-20110404123413-vmd0xo9yrx6f3uza
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: 2.4-transform-cache-sha-740932
timestamp: Mon 2011-04-04 15:37:25 +0200
message:
Merge the 2.3 branch changes up to 2.4. The final changes are
too invasive to do in a stable series (IMO).
modified:
bzrlib/_walkdirs_win32.pyx _walkdirs_win32.pyx-20080716220454-kweh3tgxez5dvw2l-2
bzrlib/config.py config.py-20051011043216-070c74f4e9e338e8
bzrlib/crash.py crash.py-20090812083334-d6volool4lktdjcx-1
bzrlib/dirstate.py dirstate.py-20060728012006-d6mvoihjb3je9peu-1
bzrlib/lockdir.py lockdir.py-20060220222025-98258adf27fbdda3
bzrlib/osutils.py osutils.py-20050309040759-eeaff12fbf77ac86
bzrlib/plugin.py plugin.py-20050622060424-829b654519533d69
bzrlib/tests/__init__.py selftest.py-20050531073622-8d0e3c8845c97a64
bzrlib/tests/test_config.py testconfig.py-20051011041908-742d0c15d8d8c8eb
bzrlib/tests/test_crash.py test_crash.py-20090820042958-jglgza3wrn03ha9e-2
bzrlib/tests/test_transform.py test_transaction.py-20060105172520-b3ffb3946550e6c4
bzrlib/transform.py transform.py-20060105172343-dd99e54394d91687
bzrlib/workingtree.py workingtree.py-20050511021032-29b6ec0a681e02e3
bzrlib/workingtree_4.py workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
doc/developers/testing.txt testing.txt-20080812140359-i70zzh6v2z7grqex-1
doc/en/release-notes/bzr-2.3.txt NEWS-20050323055033-4e00b5db738777ff
-------------- next part --------------
=== modified file 'bzrlib/_walkdirs_win32.pyx'
--- a/bzrlib/_walkdirs_win32.pyx 2010-02-17 17:11:16 +0000
+++ b/bzrlib/_walkdirs_win32.pyx 2011-04-04 11:24:50 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2008, 2009, 2010 Canonical Ltd
+# Copyright (C) 2008-2011 Canonical Ltd
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -69,9 +69,13 @@
import operator
+import os
import stat
-from bzrlib import osutils, _readdir_py
+from bzrlib import _readdir_py
+
+cdef object osutils
+osutils = None
cdef class _Win32Stat:
@@ -170,6 +174,8 @@
def top_prefix_to_starting_dir(self, top, prefix=""):
"""See DirReader.top_prefix_to_starting_dir."""
+ if osutils is None:
+ from bzrlib import osutils
return (osutils.safe_utf8(prefix), None, None, None,
osutils.safe_unicode(top))
@@ -250,3 +256,37 @@
# earlier Exception, so for now, I'm ignoring this
dirblock.sort(key=operator.itemgetter(1))
return dirblock
+
+
+def lstat(path):
+ """Equivalent to os.lstat, except match Win32ReadDir._get_stat_value.
+ """
+ return wrap_stat(os.lstat(path))
+
+
+def fstat(fd):
+ """Like os.fstat, except match Win32ReadDir._get_stat_value
+
+ :seealso: wrap_stat
+ """
+ return wrap_stat(os.fstat(fd))
+
+
+def wrap_stat(st):
+ """Return a _Win32Stat object, based on the given stat result.
+
+ On Windows, os.fstat(open(fname).fileno()) != os.lstat(fname). This is
+ generally because os.lstat and os.fstat differ in what they put into st_ino
+ and st_dev. What gets set where seems to also be dependent on the python
+ version. So we always set it to 0 to avoid worrying about it.
+ """
+ cdef _Win32Stat statvalue
+ statvalue = _Win32Stat()
+ statvalue.st_mode = st.st_mode
+ statvalue.st_ctime = st.st_ctime
+ statvalue.st_mtime = st.st_mtime
+ statvalue.st_atime = st.st_atime
+ statvalue._st_size = st.st_size
+ statvalue.st_ino = 0
+ statvalue.st_dev = 0
+ return statvalue
=== modified file 'bzrlib/config.py'
--- a/bzrlib/config.py 2011-03-31 13:35:54 +0000
+++ b/bzrlib/config.py 2011-04-04 13:37:25 +0000
@@ -63,6 +63,7 @@
"""
import os
+import string
import sys
from bzrlib import commands
@@ -441,21 +442,21 @@
the concrete policy type is checked, and finally
$EMAIL is examined.
If no username can be found, errors.NoWhoami exception is raised.
-
- TODO: Check it's reasonably well-formed.
"""
v = os.environ.get('BZR_EMAIL')
if v:
return v.decode(osutils.get_user_encoding())
-
v = self._get_user_id()
if v:
return v
-
v = os.environ.get('EMAIL')
if v:
return v.decode(osutils.get_user_encoding())
-
+ name, email = _auto_user_id()
+ if name and email:
+ return '%s <%s>' % (name, email)
+ elif email:
+ return email
raise errors.NoWhoami()
def ensure_username(self):
@@ -1407,6 +1408,86 @@
return os.path.expanduser('~/.cache')
+def _get_default_mail_domain():
+ """If possible, return the assumed default email domain.
+
+ :returns: string mail domain, or None.
+ """
+ if sys.platform == 'win32':
+ # No implementation yet; patches welcome
+ return None
+ try:
+ f = open('/etc/mailname')
+ except (IOError, OSError), e:
+ return None
+ try:
+ domain = f.read().strip()
+ return domain
+ finally:
+ f.close()
+
+
+def _auto_user_id():
+ """Calculate automatic user identification.
+
+ :returns: (realname, email), either of which may be None if they can't be
+ determined.
+
+ Only used when none is set in the environment or the id file.
+
+ This only returns an email address if we can be fairly sure the
+ address is reasonable, ie if /etc/mailname is set on unix.
+
+ This doesn't use the FQDN as the default domain because that may be
+ slow, and it doesn't use the hostname alone because that's not normally
+ a reasonable address.
+ """
+ if sys.platform == 'win32':
+ # No implementation to reliably determine Windows default mail
+ # address; please add one.
+ return None, None
+
+ default_mail_domain = _get_default_mail_domain()
+ if not default_mail_domain:
+ return None, None
+
+ import pwd
+ uid = os.getuid()
+ try:
+ w = pwd.getpwuid(uid)
+ except KeyError:
+ mutter('no passwd entry for uid %d?' % uid)
+ return None, None
+
+ # we try utf-8 first, because on many variants (like Linux),
+ # /etc/passwd "should" be in utf-8, and because it's unlikely to give
+ # false positives. (many users will have their user encoding set to
+ # latin-1, which cannot raise UnicodeError.)
+ try:
+ gecos = w.pw_gecos.decode('utf-8')
+ encoding = 'utf-8'
+ except UnicodeError:
+ try:
+ encoding = osutils.get_user_encoding()
+ gecos = w.pw_gecos.decode(encoding)
+ except UnicodeError, e:
+ mutter("cannot decode passwd entry %s" % w)
+ return None, None
+ try:
+ username = w.pw_name.decode(encoding)
+ except UnicodeError, e:
+ mutter("cannot decode passwd entry %s" % w)
+ return None, None
+
+ comma = gecos.find(',')
+ if comma == -1:
+ realname = gecos
+ else:
+ realname = gecos[:comma]
+
+ return realname, (username + '@' + default_mail_domain)
+
+
def parse_username(username):
"""Parse e-mail username and return a (name, address) tuple."""
match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
=== modified file 'bzrlib/crash.py'
--- a/bzrlib/crash.py 2011-01-20 23:07:25 +0000
+++ b/bzrlib/crash.py 2011-04-04 13:37:25 +0000
@@ -84,19 +84,27 @@
"""Report a bug by just printing a message to the user."""
trace.print_exception(exc_info, err_file)
err_file.write('\n')
- err_file.write('bzr %s on python %s (%s)\n' % \
- (bzrlib.__version__,
- bzrlib._format_version_tuple(sys.version_info),
- platform.platform(aliased=1)))
- err_file.write('arguments: %r\n' % sys.argv)
- err_file.write(
+ import textwrap
+ def print_wrapped(l):
+ err_file.write(textwrap.fill(l,
+ width=78, subsequent_indent=' ') + '\n')
+ print_wrapped('bzr %s on python %s (%s)\n' % \
+ (bzrlib.__version__,
+ bzrlib._format_version_tuple(sys.version_info),
+ platform.platform(aliased=1)))
+ print_wrapped('arguments: %r\n' % sys.argv)
+ print_wrapped(textwrap.fill(
+ 'plugins: ' + plugin.format_concise_plugin_list(),
+ width=78,
+ subsequent_indent=' ',
+ ) + '\n')
+ print_wrapped(
'encoding: %r, fsenc: %r, lang: %r\n' % (
osutils.get_user_encoding(), sys.getfilesystemencoding(),
os.environ.get('LANG')))
- err_file.write("plugins:\n")
- err_file.write(_format_plugin_list())
+ # We used to show all the plugins here, but it's too verbose.
err_file.write(
- "\n\n"
+ "\n"
"*** Bazaar has encountered an internal error. This probably indicates a\n"
" bug in Bazaar. You can help us fix it by filing a bug report at\n"
" https://bugs.launchpad.net/bzr/+filebug\n"
=== modified file 'bzrlib/dirstate.py'
--- a/bzrlib/dirstate.py 2011-01-25 22:54:08 +0000
+++ b/bzrlib/dirstate.py 2011-04-04 13:37:25 +0000
@@ -265,6 +265,17 @@
# return '%X.%X' % (int(st.st_mtime), st.st_mode)
+def _unpack_stat(packed_stat):
+ """Turn a packed_stat back into the stat fields.
+
+ This is meant as a debugging tool, should not be used in real code.
+ """
+ (st_size, st_mtime, st_ctime, st_dev, st_ino,
+ st_mode) = struct.unpack('>LLLLLL', binascii.a2b_base64(packed_stat))
+ return dict(st_size=st_size, st_mtime=st_mtime, st_ctime=st_ctime,
+ st_dev=st_dev, st_ino=st_ino, st_mode=st_mode)
+
+
class SHA1Provider(object):
"""An interface for getting sha1s of a file."""
@@ -1734,8 +1745,8 @@
self._sha_cutoff_time()
if (stat_value.st_mtime < self._cutoff_time
and stat_value.st_ctime < self._cutoff_time):
- entry[1][0] = ('f', sha1, entry[1][0][2], entry[1][0][3],
- packed_stat)
+ entry[1][0] = ('f', sha1, stat_value.st_size, entry[1][0][3],
+ packed_stat)
self._dirblock_state = DirState.IN_MEMORY_MODIFIED
def _sha_cutoff_time(self):
=== modified file 'bzrlib/lockdir.py'
--- a/bzrlib/lockdir.py 2011-01-12 20:31:15 +0000
+++ b/bzrlib/lockdir.py 2011-03-31 09:01:27 +0000
@@ -537,6 +537,17 @@
hook(hook_result)
return result
+ def lock_url_for_display(self):
+ """Give a nicely-printable representation of the URL of this lock."""
+ # As local lock urls are correct we display them.
+ # We avoid displaying remote lock urls.
+ lock_url = self.transport.abspath(self.path)
+ if lock_url.startswith('file://'):
+ lock_url = lock_url.split('.bzr/')[0]
+ else:
+ lock_url = ''
+ return lock_url
+
def wait_lock(self, timeout=None, poll=None, max_attempts=None):
"""Wait a certain period for a lock.
@@ -566,6 +577,7 @@
deadline_str = None
last_info = None
attempt_count = 0
+ lock_url = self.lock_url_for_display()
while True:
attempt_count += 1
try:
@@ -590,13 +602,6 @@
if deadline_str is None:
deadline_str = time.strftime('%H:%M:%S',
time.localtime(deadline))
- # As local lock urls are correct we display them.
- # We avoid displaying remote lock urls.
- lock_url = self.transport.abspath(self.path)
- if lock_url.startswith('file://'):
- lock_url = lock_url.split('.bzr/')[0]
- else:
- lock_url = ''
user, hostname, pid, time_ago = formatted_info
msg = ('%s lock %s ' # lock_url
'held by ' # start
=== modified file 'bzrlib/osutils.py'
--- a/bzrlib/osutils.py 2011-02-24 16:13:39 +0000
+++ b/bzrlib/osutils.py 2011-04-04 13:37:25 +0000
@@ -392,6 +392,12 @@
# These were already lazily imported into local scope
# mkdtemp = tempfile.mkdtemp
# rmtree = shutil.rmtree
+lstat = os.lstat
+fstat = os.fstat
+
+def wrap_stat(st):
+ return st
+
MIN_ABS_PATHLENGTH = 1
@@ -407,6 +413,14 @@
getcwd = _win32_getcwd
mkdtemp = _win32_mkdtemp
rename = _win32_rename
+ try:
+ from bzrlib import _walkdirs_win32
+ except ImportError:
+ pass
+ else:
+ lstat = _walkdirs_win32.lstat
+ fstat = _walkdirs_win32.fstat
+ wrap_stat = _walkdirs_win32.wrap_stat
MIN_ABS_PATHLENGTH = 3
=== modified file 'bzrlib/plugin.py'
--- a/bzrlib/plugin.py 2011-01-20 01:02:34 +0000
+++ b/bzrlib/plugin.py 2011-04-04 13:37:25 +0000
@@ -451,6 +451,17 @@
return result
+def format_concise_plugin_list():
+ """Return a string holding a concise list of plugins and their version.
+ """
+ items = []
+ for name, a_plugin in sorted(plugins().items()):
+ items.append("%s[%s]" %
+ (name, a_plugin.__version__))
+ return ', '.join(items)
+
+
+
class PluginsHelpIndex(object):
"""A help index that returns help topics for plugins."""
=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py 2011-03-30 11:34:31 +0000
+++ b/bzrlib/tests/__init__.py 2011-04-04 13:37:25 +0000
@@ -1267,11 +1267,15 @@
'st_mtime did not match')
self.assertEqual(expected.st_ctime, actual.st_ctime,
'st_ctime did not match')
- if sys.platform != 'win32':
+ if sys.platform == 'win32':
# On Win32 both 'dev' and 'ino' cannot be trusted. In python2.4 it
# is 'dev' that varies, in python 2.5 (6?) it is st_ino that is
- # odd. Regardless we shouldn't actually try to assert anything
- # about their values
+ # odd. We just force it to always be 0 to avoid any problems.
+ self.assertEqual(0, expected.st_dev)
+ self.assertEqual(0, actual.st_dev)
+ self.assertEqual(0, expected.st_ino)
+ self.assertEqual(0, actual.st_ino)
+ else:
self.assertEqual(expected.st_dev, actual.st_dev,
'st_dev did not match')
self.assertEqual(expected.st_ino, actual.st_ino,
=== modified file 'bzrlib/tests/test_config.py'
--- a/bzrlib/tests/test_config.py 2011-02-25 12:12:39 +0000
+++ b/bzrlib/tests/test_config.py 2011-04-04 13:37:25 +0000
@@ -42,6 +42,7 @@
)
from bzrlib.tests import (
features,
+ TestSkipped,
scenarios,
)
from bzrlib.util.configobj import configobj
@@ -2469,3 +2470,25 @@
# test_user_prompted ?
class TestAuthenticationRing(tests.TestCaseWithTransport):
pass
+
+
+class TestAutoUserId(tests.TestCase):
+ """Test inferring an automatic user name."""
+
+ def test_auto_user_id(self):
+ """Automatic inference of user name.
+
+ This is a bit hard to test in an isolated way, because it depends on
+ system functions that go direct to /etc or perhaps somewhere else.
+ But it's reasonable to say that on Unix, with an /etc/mailname, we ought
+ to be able to choose a user name with no configuration.
+ """
+ if sys.platform == 'win32':
+ raise TestSkipped("User name inference not implemented on win32")
+ realname, address = config._auto_user_id()
+ if os.path.exists('/etc/mailname'):
+ self.assertTrue(realname)
+ self.assertTrue(address)
+ else:
+ self.assertEquals((None, None), (realname, address))
+
=== modified file 'bzrlib/tests/test_crash.py'
--- a/bzrlib/tests/test_crash.py 2011-01-18 00:41:29 +0000
+++ b/bzrlib/tests/test_crash.py 2011-04-04 13:37:25 +0000
@@ -15,12 +15,12 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+import doctest
+import os
from StringIO import StringIO
import sys
-
-import os
-
+from testtools.matchers import DocTestMatches
from bzrlib import (
config,
@@ -80,3 +80,45 @@
self.assertContainsRe(
report,
'Failed to load plugin foo')
+
+
+class TestNonApportReporting(tests.TestCase):
+ """Reporting of crash-type bugs without apport.
+
+ This should work in all environments.
+ """
+
+ def setup_fake_plugins(self):
+ def fake_plugins():
+ fake = plugin.PlugIn('fake_plugin', plugin)
+ fake.version_info = lambda: (1, 2, 3)
+ return {"fake_plugin": fake}
+ self.overrideAttr(plugin, 'plugins', fake_plugins)
+
+ def test_report_bug_legacy(self):
+ self.setup_fake_plugins()
+ err_file = StringIO()
+ try:
+ raise AssertionError("my error")
+ except AssertionError, e:
+ pass
+ crash.report_bug_legacy(sys.exc_info(), err_file)
+ self.assertThat(
+ err_file.getvalue(),
+ DocTestMatches("""\
+bzr: ERROR: exceptions.AssertionError: my error
+
+Traceback (most recent call last):
+ ...
+AssertionError: my error
+
+bzr ... on python ...
+arguments: ...
+plugins: fake_plugin[1.2.3]
+encoding: ...
+
+*** Bazaar has encountered an internal error. This probably indicates a
+ bug in Bazaar. You can help us fix it by filing a bug report at
+ https://bugs.launchpad.net/bzr/+filebug
+ including this traceback and a description of the problem.
+""", flags=doctest.ELLIPSIS|doctest.REPORT_UDIFF))
=== modified file 'bzrlib/tests/test_transform.py'
--- a/bzrlib/tests/test_transform.py 2011-01-13 01:29:41 +0000
+++ b/bzrlib/tests/test_transform.py 2011-04-04 12:34:13 +0000
@@ -2062,6 +2062,42 @@
self.assertEqual('file.moved', target.id2path('lower-id'))
self.assertEqual('FILE', target.id2path('upper-id'))
+ def test_build_tree_observes_sha(self):
+ source = self.make_branch_and_tree('source')
+ self.build_tree(['source/file1', 'source/dir/', 'source/dir/file2'])
+ source.add(['file1', 'dir', 'dir/file2'],
+ ['file1-id', 'dir-id', 'file2-id'])
+ source.commit('new files')
+ target = self.make_branch_and_tree('target')
+ target.lock_write()
+ self.addCleanup(target.unlock)
+ # We make use of the fact that DirState caches its cutoff time. So we
+ # set the 'safe' time to one minute in the future.
+ state = target.current_dirstate()
+ state._cutoff_time = time.time() + 60
+ build_tree(source.basis_tree(), target)
+ entry1_sha = osutils.sha_file_by_name('source/file1')
+ entry2_sha = osutils.sha_file_by_name('source/dir/file2')
+ # entry[1] is the state information, entry[1][0] is the state of the
+ # working tree, entry[1][0][1] is the sha value for the current working
+ # tree
+ entry1 = state._get_entry(0, path_utf8='file1')
+ self.assertEqual(entry1_sha, entry1[1][0][1])
+ # The 'size' field must also be set.
+ self.assertEqual(25, entry1[1][0][2])
+ entry1_state = entry1[1][0]
+ entry2 = state._get_entry(0, path_utf8='dir/file2')
+ self.assertEqual(entry2_sha, entry2[1][0][1])
+ self.assertEqual(29, entry2[1][0][2])
+ entry2_state = entry2[1][0]
+ # Now, make sure that we don't have to re-read the content. The
+ # packed_stat should match exactly.
+ self.assertEqual(entry1_sha, target.get_file_sha1('file1-id', 'file1'))
+ self.assertEqual(entry2_sha,
+ target.get_file_sha1('file2-id', 'dir/file2'))
+ self.assertEqual(entry1_state, entry1[1][0])
+ self.assertEqual(entry2_state, entry2[1][0])
+
class TestCommitTransform(tests.TestCaseWithTransport):
=== modified file 'bzrlib/transform.py'
--- a/bzrlib/transform.py 2011-01-13 05:01:38 +0000
+++ b/bzrlib/transform.py 2011-04-04 13:37:25 +0000
@@ -105,6 +105,8 @@
self._new_parent = {}
# mapping of trans_id with new contents -> new file_kind
self._new_contents = {}
+ # mapping of trans_id => (sha1 of content, stat_value)
+ self._observed_sha1s = {}
# Set of trans_ids whose contents will be removed
self._removed_contents = set()
# Mapping of trans_id -> new execute-bit value
@@ -1271,12 +1273,26 @@
f.close()
os.unlink(name)
raise
-
- f.writelines(contents)
+ if contents.__class__ is list:
+ sha_digest = osutils.sha_strings(contents)
+ f.writelines(contents)
+ else:
+ sha_value = osutils.sha()
+ def observe_sha1(contents):
+ sha_value_update = sha_value.update
+ for content in contents:
+ sha_value_update(content)
+ yield content
+ f.writelines(observe_sha1(contents))
+ sha_digest = sha_value.hexdigest()
finally:
f.close()
self._set_mtime(name)
self._set_mode(trans_id, mode_id, S_ISREG)
+ # It is unfortunate we have to use lstat instead of fstat, but we just
+ # used utime and chmod on the file, so we need the accurate final
+ # details.
+ self._observed_sha1s[trans_id] = (sha_digest, osutils.lstat(name))
def _read_file_chunks(self, trans_id):
cur_file = open(self._limbo_name(trans_id), 'rb')
@@ -1341,6 +1357,8 @@
def cancel_creation(self, trans_id):
"""Cancel the creation of new file contents."""
del self._new_contents[trans_id]
+ if trans_id in self._observed_sha1s:
+ del self._observed_sha1s[trans_id]
children = self._limbo_children.get(trans_id)
# if this is a limbo directory with children, move them before removing
# the directory
@@ -1702,6 +1720,7 @@
finally:
child_pb.finished()
self._tree.apply_inventory_delta(inventory_delta)
+ self._apply_observed_sha1s()
self._done = True
self.finalize()
return _TransformResults(modified_paths, self.rename_count)
@@ -1827,6 +1846,9 @@
raise
else:
self.rename_count += 1
+ # TODO: if trans_id in self._observed_sha1s, we should
+ # re-stat the final target, since ctime will be
+ # updated by the change.
if (trans_id in self._new_contents or
self.path_changed(trans_id)):
if trans_id in self._new_contents:
@@ -1838,6 +1860,29 @@
self._new_contents.clear()
return modified_paths
+ def _apply_observed_sha1s(self):
+ """After we have finished renaming everything, update observed sha1s
+
+ This has to be done after self._tree.apply_inventory_delta, otherwise
+ it doesn't know anything about the files we are updating. Also, we want
+ to do this as late as possible, so that most entries end up cached.
+ """
+ # TODO: this doesn't update the stat information for directories. So
+ # the first 'bzr status' will still need to rewrite
+ # .bzr/checkout/dirstate. However, we at least don't need to
+ # re-read all of the files.
+ # TODO: If the operation took a while, we could do a time.sleep(3) here
+ # to allow the clock to tick over and ensure we won't have any
+ # problems. (we could observe start time, and finish time, and if
+ # it is less than eg 10% overhead, add a sleep call.)
+ paths = FinalPaths(self)
+ for trans_id, observed in self._observed_sha1s.iteritems():
+ path = paths.get_path(trans_id)
+ # We could get the file_id, but dirstate prefers to use the path
+ # anyway, and it is 'cheaper' to determine.
+ # file_id = self._new_id[trans_id]
+ self._tree._observed_sha1(None, path, observed)
+
class TransformPreview(DiskTreeTransform):
"""A TreeTransform for generating preview trees.
=== modified file 'bzrlib/workingtree.py'
--- a/bzrlib/workingtree.py 2011-03-07 15:33:31 +0000
+++ b/bzrlib/workingtree.py 2011-04-04 13:37:25 +0000
@@ -526,7 +526,7 @@
return self.get_file_with_stat(file_id, path, filtered=filtered)[0]
def get_file_with_stat(self, file_id, path=None, filtered=True,
- _fstat=os.fstat):
+ _fstat=osutils.fstat):
"""See Tree.get_file_with_stat."""
if path is None:
path = self.id2path(file_id)
=== modified file 'bzrlib/workingtree_4.py'
--- a/bzrlib/workingtree_4.py 2011-02-11 17:58:56 +0000
+++ b/bzrlib/workingtree_4.py 2011-04-04 13:37:25 +0000
@@ -369,7 +369,7 @@
state = self.current_dirstate()
if stat_value is None:
try:
- stat_value = os.lstat(file_abspath)
+ stat_value = osutils.lstat(file_abspath)
except OSError, e:
if e.errno == errno.ENOENT:
return None
@@ -478,7 +478,7 @@
self._must_be_locked()
if not path:
path = self.id2path(file_id)
- mode = os.lstat(self.abspath(path)).st_mode
+ mode = osutils.lstat(self.abspath(path)).st_mode
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
def all_file_ids(self):
=== modified file 'doc/developers/testing.txt'
--- a/doc/developers/testing.txt 2011-02-03 00:39:52 +0000
+++ b/doc/developers/testing.txt 2011-04-04 13:37:25 +0000
@@ -339,6 +339,11 @@
__ http://docs.python.org/lib/module-doctest.html
+There is an `assertDoctestExampleMatches` method in
+`bzrlib.tests.TestCase` that allows you to match against doctest-style
+string templates (including ``...`` to skip sections) from regular Python
+tests.
+
Shell-like tests
----------------
=== modified file 'doc/en/release-notes/bzr-2.3.txt'
--- a/doc/en/release-notes/bzr-2.3.txt 2011-03-24 11:41:42 +0000
+++ b/doc/en/release-notes/bzr-2.3.txt 2011-04-04 13:37:25 +0000
@@ -39,15 +39,37 @@
.. Fixes for situations where bzr would previously crash or give incorrect
or undesirable results.
+* Bazaar now infers the default user email address on Unix from the local
+ account name plus the contents of ``/etc/mailname`` if that file exists.
+ In particular, this means that committing as root through etckeeper will
+ normally not require running ``bzr whoami`` first.
+ (Martin Pool, #616878)
+
* ``bzr push`` into a repository (that doesn't have a branch), will no
longer copy all revisions in the repository. Only the ones in the
ancestry of the source branch, like it does in all other cases.
(John Arbash Meinel, #465517)
+* Fix ``UnboundLocalError: local variable 'lock_url' in wait_lock`` error,
+ especially while trying to save configuration from QBzr.
+ (Martin Pool, #733136)
+
* Fix "Unable to obtain lock" error when pushing to a bound branch if tags
had changed. Bazaar was attempting to open and lock the master branch
twice in this case. (Andrew Bennetts, #733350)
+* ``TreeTransform`` now calls ``_observed_sha1`` for content that it
+ creates. This means that ``merge`` and ``checkout`` should be able to
+ cache the sha values, and avoid re-reading the files on the next ``bzr
+ status`` that gets run. Further, on Windows we now properly suppress
+ ``st_dev`` and ``st_ino`` so that commit also avoids re-doing the work.
+ (John Arbash Meinel, #740932)
+
+* When reporting a crash without apport, don't print the full list of
+ plugins because it's often too long.
+ (Martin Pool, #716389)
+
+
Documentation
*************
@@ -79,7 +101,6 @@
(<http://psf.upfronthosting.co.za/roundup/tracker/issue8194> should be fixed
in python > 2.7.1). (Vincent Ladeuil, #654733)
-
bzr 2.3.1
#########
More information about the bazaar-commits
mailing list