Rev 2248: [merge] bzr.dev 2252 in http://bzr.arbash-meinel.com/branches/bzr/0.15-dev/annotate_revnos
John Arbash Meinel
john at arbash-meinel.com
Thu Feb 1 21:29:25 GMT 2007
At http://bzr.arbash-meinel.com/branches/bzr/0.15-dev/annotate_revnos
------------------------------------------------------------
revno: 2248
revision-id: john at arbash-meinel.com-20070201212919-s0s8iwvi8lowk0w0
parent: john at arbash-meinel.com-20070201163300-jp0cs02xz90leqpf
parent: pqm at pqm.ubuntu.com-20070201203641-a125a85aee82c725
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: annotate_revnos
timestamp: Thu 2007-02-01 15:29:19 -0600
message:
[merge] bzr.dev 2252
added:
bzrlib/tests/branch_implementations/test_hooks.py test_hooks.py-20070129154855-blhpwxmvjs07waei-1
bzrlib/tests/branch_implementations/test_push.py test_push.py-20070130153159-fhfap8uoifevg30j-1
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/branch.py branch.py-20050309040759-e4baf4e0d046576e
bzrlib/builtins.py builtins.py-20050830033751-fc01482b9ca23183
bzrlib/errors.py errors.py-20050309040759-20512168c4e14fbd
bzrlib/help_topics.py help_topics.py-20060920210027-rnim90q9e0bwxvy4-1
bzrlib/lockdir.py lockdir.py-20060220222025-98258adf27fbdda3
bzrlib/merge.py merge.py-20050513021216-953b65a438527106
bzrlib/osutils.py osutils.py-20050309040759-eeaff12fbf77ac86
bzrlib/tests/__init__.py selftest.py-20050531073622-8d0e3c8845c97a64
bzrlib/tests/branch_implementations/__init__.py __init__.py-20060123013057-b12a52c3f361daf4
bzrlib/tests/branch_implementations/test_bound_sftp.py test_bound_sftp.py-20051231055311-2f96048c4f0940ef
bzrlib/tests/branch_implementations/test_pull.py test_pull.py-20060410103942-83c35b26657414fc
bzrlib/tests/test_branch.py test_branch.py-20060116013032-97819aa07b8ab3b5
bzrlib/tests/test_errors.py test_errors.py-20060210110251-41aba2deddf936a8
bzrlib/tests/test_lockdir.py test_lockdir.py-20060220222025-33d4221569a3d600
bzrlib/tests/test_merge.py testmerge.py-20050905070950-c1b5aa49ff911024
bzrlib/tests/test_osutils.py test_osutils.py-20051201224856-e48ee24c12182989
bzrlib/tests/test_selftest.py test_selftest.py-20051202044319-c110a115d8c0456a
bzrlib/transform.py transform.py-20060105172343-dd99e54394d91687
------------------------------------------------------------
revno: 2245.1.7
merged: pqm at pqm.ubuntu.com-20070201203641-a125a85aee82c725
parent: pqm at pqm.ubuntu.com-20070201202403-7e92ef4d6842ba85
parent: john at arbash-meinel.com-20070201144953-d877vy9zbvxr5q98
committer: Canonical.com Patch Queue Manager<pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Thu 2007-02-01 20:36:41 +0000
message:
(John Arbash Meinel) hard-code the whitespace chars to avoid problems in some locales.
------------------------------------------------------------
revno: 2245.1.4.2.1
merged: john at arbash-meinel.com-20070201144953-d877vy9zbvxr5q98
parent: pqm at pqm.ubuntu.com-20070131184047-424584b0fabcee96
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: jam-integration
timestamp: Thu 2007-02-01 08:49:53 -0600
message:
(John Arbash Meinel) hard-code the whitespace chars to avoid problems in some locales.
------------------------------------------------------------
revno: 2245.1.6
merged: pqm at pqm.ubuntu.com-20070201202403-7e92ef4d6842ba85
parent: pqm at pqm.ubuntu.com-20070201175351-9ba49ec1a0744c97
parent: abentley at panoramicfeedback.com-20070201145904-nrzbl3vkwjssrkhb
committer: Canonical.com Patch Queue Manager<pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Thu 2007-02-01 20:24:03 +0000
message:
Treat Permission Denied as a lock failure, not lock contention
------------------------------------------------------------
revno: 1551.2.49.1.40.1.22.1.42.1.31.1.4
merged: abentley at panoramicfeedback.com-20070201145904-nrzbl3vkwjssrkhb
parent: abentley at panoramicfeedback.com-20070131184912-1n4p0avc2qw5qyax
committer: Aaron Bentley <abentley at panoramicfeedback.com>
branch nick: Aaron's mergeable stuff
timestamp: Thu 2007-02-01 09:59:04 -0500
message:
Update to skip on win32
------------------------------------------------------------
revno: 1551.2.49.1.40.1.22.1.42.1.31.1.3
merged: abentley at panoramicfeedback.com-20070131184912-1n4p0avc2qw5qyax
parent: aaron.bentley at utoronto.ca-20070131035136-exu2pa898yr2gzen
committer: Aaron Bentley <abentley at panoramicfeedback.com>
branch nick: Aaron's mergeable stuff
timestamp: Wed 2007-01-31 13:49:12 -0500
message:
Lock attempts don't treat permission problems as lock contention
------------------------------------------------------------
revno: 2245.1.5
merged: pqm at pqm.ubuntu.com-20070201175351-9ba49ec1a0744c97
parent: pqm at pqm.ubuntu.com-20070131184047-424584b0fabcee96
parent: robertc at robertcollins.net-20070201171842-aw4059y8znmigwgn
committer: Canonical.com Patch Queue Manager<pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Thu 2007-02-01 17:53:51 +0000
message:
(robertc) Split branch pushing out of branch pulling.
------------------------------------------------------------
revno: 2245.1.4.1.1
merged: robertc at robertcollins.net-20070201171842-aw4059y8znmigwgn
parent: pqm at pqm.ubuntu.com-20070131184047-424584b0fabcee96
parent: robertc at robertcollins.net-20070130211105-u8p44qh31vsn4xh3
committer: Robert Collins <robertc at robertcollins.net>
branch nick: integration
timestamp: Fri 2007-02-02 04:18:42 +1100
message:
(robertc) Split branch pushing out of branch pulling.
------------------------------------------------------------
revno: 2245.3.3
merged: robertc at robertcollins.net-20070130211105-u8p44qh31vsn4xh3
parent: robertc at robertcollins.net-20070130210611-6ogb9vztebubsqyx
committer: Robert Collins <robertc at robertcollins.net>
branch nick: split-branch-pull
timestamp: Wed 2007-01-31 08:11:05 +1100
message:
Add a NEWS entry.
------------------------------------------------------------
revno: 2245.3.2
merged: robertc at robertcollins.net-20070130210611-6ogb9vztebubsqyx
parent: robertc at robertcollins.net-20070130205825-cagx4gvf17ioe2i5
committer: Robert Collins <robertc at robertcollins.net>
branch nick: split-branch-pull
timestamp: Wed 2007-01-31 08:06:11 +1100
message:
Update cmd_push to invoke the correct 'push' method on branch, rather than pull. This does not alter tests because the behaviour for push and pull is still symmetrical.
------------------------------------------------------------
revno: 2245.3.1
merged: robertc at robertcollins.net-20070130205825-cagx4gvf17ioe2i5
parent: pqm at pqm.ubuntu.com-20070125194626-4ded330415b7276d
committer: Robert Collins <robertc at robertcollins.net>
branch nick: split-branch-pull
timestamp: Wed 2007-01-31 07:58:25 +1100
message:
Split branch pushing out of branch pulling.
------------------------------------------------------------
revno: 2245.1.4
merged: pqm at pqm.ubuntu.com-20070131184047-424584b0fabcee96
parent: pqm at pqm.ubuntu.com-20070131165725-e3091cb8d282ef90
parent: john at arbash-meinel.com-20070131174855-gxkjd9rvy17uc6ko
committer: Canonical.com Patch Queue Manager<pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Wed 2007-01-31 18:40:47 +0000
message:
(John Arbash Meinel) switch from looping over f.write() to f.writelines()
------------------------------------------------------------
revno: 2245.1.2.1.2
merged: john at arbash-meinel.com-20070131174855-gxkjd9rvy17uc6ko
parent: john at arbash-meinel.com-20070131163348-kkwfh7hvvm39tx8y
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: jam-integration
timestamp: Wed 2007-01-31 11:48:55 -0600
message:
Switch from for line in foo: f.write(line) to f.writelines(foo)
------------------------------------------------------------
revno: 2245.1.3
merged: pqm at pqm.ubuntu.com-20070131165725-e3091cb8d282ef90
parent: pqm at pqm.ubuntu.com-20070131140456-56881c31a01089a3
parent: john at arbash-meinel.com-20070131163348-kkwfh7hvvm39tx8y
committer: Canonical.com Patch Queue Manager<pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Wed 2007-01-31 16:57:25 +0000
message:
fix --Derror => -Derror (trivial)
------------------------------------------------------------
revno: 2245.1.2.1.1
merged: john at arbash-meinel.com-20070131163348-kkwfh7hvvm39tx8y
parent: pqm at pqm.ubuntu.com-20070131140456-56881c31a01089a3
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: jam-integration
timestamp: Wed 2007-01-31 10:33:48 -0600
message:
fix --Derror => -Derror (trivial)
------------------------------------------------------------
revno: 2245.1.2
merged: pqm at pqm.ubuntu.com-20070131140456-56881c31a01089a3
parent: pqm at pqm.ubuntu.com-20070130211230-64c2d9b4bce9304f
parent: aaron.bentley at utoronto.ca-20070131035136-exu2pa898yr2gzen
committer: Canonical.com Patch Queue Manager<pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Wed 2007-01-31 14:04:56 +0000
message:
Handle merge with dangling inventory entries
------------------------------------------------------------
revno: 1551.2.49.1.40.1.22.1.42.1.31.1.2
merged: aaron.bentley at utoronto.ca-20070131035136-exu2pa898yr2gzen
parent: aaron.bentley at utoronto.ca-20070131020421-a9fhra61hiwr0kcb
committer: Aaron Bentley <aaron.bentley at utoronto.ca>
branch nick: Aaron's mergeable stuff
timestamp: Tue 2007-01-30 22:51:36 -0500
message:
Handle merge with dangling inventory entries
------------------------------------------------------------
revno: 1551.2.49.1.40.1.22.1.42.1.31.1.1
merged: aaron.bentley at utoronto.ca-20070131020421-a9fhra61hiwr0kcb
parent: abentley at panoramicfeedback.com-20070111155749-v70rw01ug96bs1ll
parent: pqm at pqm.ubuntu.com-20070125194626-4ded330415b7276d
committer: Aaron Bentley <aaron.bentley at utoronto.ca>
branch nick: Aaron's mergeable stuff
timestamp: Tue 2007-01-30 21:04:21 -0500
message:
Merge bzr.dev
------------------------------------------------------------
revno: 2245.1.1
merged: pqm at pqm.ubuntu.com-20070130211230-64c2d9b4bce9304f
parent: pqm at pqm.ubuntu.com-20070125194626-4ded330415b7276d
parent: robertc at robertcollins.net-20070130115230-2052dzn5xo9h6o07
committer: Canonical.com Patch Queue Manager<pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Tue 2007-01-30 21:12:30 +0000
message:
(robertc) Add Branch hooks faciity, allowing clean creation and management of hooks around branch API calls.
------------------------------------------------------------
revno: 2245.2.3
merged: robertc at robertcollins.net-20070130115230-2052dzn5xo9h6o07
parent: robertc at robertcollins.net-20070130104104-wsikhrgretspg86m
committer: Robert Collins <robertc at robertcollins.net>
branch nick: branch-hook
timestamp: Tue 2007-01-30 22:52:30 +1100
message:
Add install_hook to the BranchHooks class as the official means for installing a hook.
------------------------------------------------------------
revno: 2245.2.2
merged: robertc at robertcollins.net-20070130104104-wsikhrgretspg86m
parent: robertc at robertcollins.net-20070129165849-409f5714fa7ebe48
committer: Robert Collins <robertc at robertcollins.net>
branch nick: branch-hook
timestamp: Tue 2007-01-30 21:41:04 +1100
message:
Remove the static DefaultHooks method from Branch, replacing it with a derived dict BranchHooks object, which is easier to use and provides a place to put the policy-checking add method discussed on list.
------------------------------------------------------------
revno: 2245.2.1
merged: robertc at robertcollins.net-20070129165849-409f5714fa7ebe48
parent: pqm at pqm.ubuntu.com-20070125194626-4ded330415b7276d
committer: Robert Collins <robertc at robertcollins.net>
branch nick: branch-hook
timestamp: Tue 2007-01-30 03:58:49 +1100
message:
New Branch hooks facility, with one initial hook 'set_rh' which triggers
whenever the revision history is set. This allows triggering on e.g.
push, pull, commit, and so on. Developed for use with the branchrss
plugin. See bzrlib/tests/branch_implementations/test_hooks for more
details. (Robert Collins)
-------------- next part --------------
=== added file 'bzrlib/tests/branch_implementations/test_hooks.py'
--- a/bzrlib/tests/branch_implementations/test_hooks.py 1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/branch_implementations/test_hooks.py 2007-01-30 10:41:04 +0000
@@ -0,0 +1,67 @@
+# Copyright (C) 2007 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
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""Tests that branch classes implement hook callouts correctly."""
+
+from bzrlib.branch import Branch
+from bzrlib.tests import TestCaseWithMemoryTransport
+
+
+class TestPushHook(TestCaseWithMemoryTransport):
+
+ def setUp(self):
+ self.hook_calls = []
+ TestCaseWithMemoryTransport.setUp(self)
+
+ def capture_set_rh_hook(self, branch, rev_history):
+ """Capture post push hook calls to self.hook_calls.
+
+ The call is logged, as is some state of the two branches.
+ """
+ self.hook_calls.append(
+ ('set_rh', branch, rev_history, branch.is_locked()))
+
+ def test_set_rh_empty_history(self):
+ branch = self.make_branch('source')
+ Branch.hooks['set_rh'].append(self.capture_set_rh_hook)
+ branch.set_revision_history([])
+ self.assertEqual(self.hook_calls,
+ [('set_rh', branch, [], True)])
+
+ def test_set_rh_nonempty_history(self):
+ branch = self.make_branch('source')
+ Branch.hooks['set_rh'].append(self.capture_set_rh_hook)
+ branch.set_revision_history([u'foo'])
+ self.assertEqual(self.hook_calls,
+ [('set_rh', branch, [u'foo'], True)])
+
+ def test_set_rh_branch_is_locked(self):
+ branch = self.make_branch('source')
+ Branch.hooks['set_rh'].append(self.capture_set_rh_hook)
+ branch.set_revision_history([])
+ self.assertEqual(self.hook_calls,
+ [('set_rh', branch, [], True)])
+
+ def test_set_rh_calls_all_hooks_no_errors(self):
+ branch = self.make_branch('source')
+ Branch.hooks['set_rh'].append(self.capture_set_rh_hook)
+ Branch.hooks['set_rh'].append(self.capture_set_rh_hook)
+ branch.set_revision_history([])
+ self.assertEqual(self.hook_calls,
+ [('set_rh', branch, [], True),
+ ('set_rh', branch, [], True),
+ ])
+
=== added file 'bzrlib/tests/branch_implementations/test_push.py'
--- a/bzrlib/tests/branch_implementations/test_push.py 1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/branch_implementations/test_push.py 2007-01-30 20:58:25 +0000
@@ -0,0 +1,79 @@
+# Copyright (C) 2004, 2005, 2007 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
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""Tests for branch.push behaviour."""
+
+import os
+
+from bzrlib.branch import Branch
+from bzrlib import errors
+from bzrlib.tests import TestCaseWithTransport
+
+
+class TestPush(TestCaseWithTransport):
+
+ def test_push_convergence_simple(self):
+ # when revisions are pushed, the left-most accessible parents must
+ # become the revision-history.
+ mine = self.make_branch_and_tree('mine')
+ mine.commit('1st post', rev_id='P1', allow_pointless=True)
+ other = mine.bzrdir.sprout('other').open_workingtree()
+ other.commit('my change', rev_id='M1', allow_pointless=True)
+ mine.merge_from_branch(other.branch)
+ mine.commit('merge my change', rev_id='P2')
+ mine.branch.push(other.branch)
+ self.assertEqual(['P1', 'P2'], other.branch.revision_history())
+
+ def test_push_merged_indirect(self):
+ # it should be possible to do a push from one branch into another
+ # when the tip of the target was merged into the source branch
+ # via a third branch - so its buried in the ancestry and is not
+ # directly accessible.
+ mine = self.make_branch_and_tree('mine')
+ mine.commit('1st post', rev_id='P1', allow_pointless=True)
+ target = mine.bzrdir.sprout('target').open_workingtree()
+ target.commit('my change', rev_id='M1', allow_pointless=True)
+ other = mine.bzrdir.sprout('other').open_workingtree()
+ other.merge_from_branch(target.branch)
+ other.commit('merge my change', rev_id='O2')
+ mine.merge_from_branch(other.branch)
+ mine.commit('merge other', rev_id='P2')
+ mine.branch.push(target.branch)
+ self.assertEqual(['P1', 'P2'], target.branch.revision_history())
+
+ def test_push_to_checkout_updates_master(self):
+ """Pushing into a checkout updates the checkout and the master branch"""
+ master_tree = self.make_branch_and_tree('master')
+ rev1 = master_tree.commit('master')
+ checkout = master_tree.branch.create_checkout('checkout')
+
+ other = master_tree.branch.bzrdir.sprout('other').open_workingtree()
+ rev2 = other.commit('other commit')
+ # now push, which should update both checkout and master.
+ other.branch.push(checkout.branch)
+ self.assertEqual([rev1, rev2], checkout.branch.revision_history())
+ self.assertEqual([rev1, rev2], master_tree.branch.revision_history())
+
+ def test_push_raises_specific_error_on_master_connection_error(self):
+ master_tree = self.make_branch_and_tree('master')
+ checkout = master_tree.branch.create_checkout('checkout')
+ other = master_tree.branch.bzrdir.sprout('other').open_workingtree()
+ # move the branch out of the way on disk to cause a connection
+ # error.
+ os.rename('master', 'master_gone')
+ # try to push, which should raise a BoundBranchConnectionFailure.
+ self.assertRaises(errors.BoundBranchConnectionFailure,
+ other.branch.push, checkout.branch)
=== modified file 'NEWS'
--- a/NEWS 2007-01-29 21:11:28 +0000
+++ b/NEWS 2007-02-01 21:29:19 +0000
@@ -25,12 +25,24 @@
versionedfiles, repositories, branches, and working trees
(Aaron Bentley)
+ * New Branch hooks facility, with one initial hook 'set_rh' which triggers
+ whenever the revision history is set. This allows triggering on e.g.
+ push, pull, commit, and so on. Developed for use with the branchrss
+ plugin. See bzrlib.branch.BranchHooks for more details. (Robert Collins)
+
+ * New method ``Branch.push()`` which should be used when pushing from a
+ branch as it makes performance and policy decisions to match the UI
+ level command ``push``. (Robert Collins).
+
BUGFIXES:
* ``bzr annotate`` now uses dotted revnos from the viewpoint of the
branch, rather than the last changed revision of the file.
(John Arbash Meinel, #82158)
+ * Lock operations no longer hang if they encounter a permission problem.
+ (Aaron Bentley)
+
TESTING:
* New ``--first`` option to ``bzr selftest`` to run specified tests
=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py 2007-01-17 15:37:08 +0000
+++ b/bzrlib/branch.py 2007-02-01 17:18:42 +0000
@@ -81,6 +81,8 @@
base
Base directory/url of the branch.
+
+ hooks: An instance of BranchHooks.
"""
# this is really an instance variable - FIXME move it there
# - RBC 20060112
@@ -375,8 +377,19 @@
return history[revno - 1]
def pull(self, source, overwrite=False, stop_revision=None):
+ """Mirror source into this branch.
+
+ This branch is considered to be 'local', having low latency.
+ """
raise NotImplementedError(self.pull)
+ def push(self, target, overwrite=False, stop_revision=None):
+ """Mirror this branch into target.
+
+ This branch is considered to be 'local', having low latency.
+ """
+ raise NotImplementedError(self.push)
+
def basis_tree(self):
"""Return `Tree` object for last revision."""
return self.repository.revision_tree(self.last_revision())
@@ -599,7 +612,7 @@
format = self.repository.bzrdir.cloning_metadir()
return format
- def create_checkout(self, to_location, revision_id=None,
+ def create_checkout(self, to_location, revision_id=None,
lightweight=False):
"""Create a checkout of a branch.
@@ -716,6 +729,45 @@
return self.get_format_string().rstrip()
+class BranchHooks(dict):
+ """A dictionary mapping hook name to a list of callables for branch hooks.
+
+ e.g. ['set_rh'] Is the list of items to be called when the
+ set_revision_history function is invoked.
+ """
+
+ def __init__(self):
+ """Create the default hooks.
+
+ These are all empty initially, because by default nothing should get
+ notified.
+ """
+ dict.__init__(self)
+ # invoked whenever the revision history has been set
+ # with set_revision_history. The api signature is
+ # (branch, revision_history), and the branch will
+ # be write-locked. Introduced in 0.15.
+ self['set_rh'] = []
+
+ def install_hook(self, hook_name, a_callable):
+ """Install a_callable in to the hook hook_name.
+
+ :param hook_name: A hook name. See the __init__ method of BranchHooks
+ for the complete list of hooks.
+ :param a_callable: The callable to be invoked when the hook triggers.
+ The exact signature will depend on the hook - see the __init__
+ method of BranchHooks for details on each hook.
+ """
+ try:
+ self[hook_name].append(a_callable)
+ except KeyError:
+ raise errors.UnknownHook('branch', hook_name)
+
+
+# install the default hooks into the Branch class.
+Branch.hooks = BranchHooks()
+
+
class BzrBranchFormat4(BranchFormat):
"""Bzr branch format 4.
@@ -1101,6 +1153,8 @@
# this call is disabled because revision_history is
# not really an object yet, and the transaction is for objects.
# transaction.register_clean(history)
+ for hook in Branch.hooks['set_rh']:
+ hook(self, rev_history)
@needs_read_lock
def revision_history(self):
@@ -1205,6 +1259,24 @@
finally:
source.unlock()
+ @needs_read_lock
+ def push(self, target, overwrite=False, stop_revision=None):
+ """See Branch.push."""
+ target.lock_write()
+ try:
+ old_count = len(target.revision_history())
+ try:
+ target.update_revisions(self, stop_revision)
+ except DivergedBranches:
+ if not overwrite:
+ raise
+ if overwrite:
+ target.set_revision_history(self.revision_history())
+ new_count = len(target.revision_history())
+ return new_count - old_count
+ finally:
+ target.unlock()
+
def get_parent(self):
"""See Branch.get_parent."""
@@ -1283,7 +1355,7 @@
@needs_write_lock
def pull(self, source, overwrite=False, stop_revision=None):
- """Updates branch.pull to be bound branch aware."""
+ """Extends branch.pull to be bound branch aware."""
bound_location = self.get_bound_location()
if source.base != bound_location:
# not pulling from master, so we need to update master.
@@ -1293,6 +1365,22 @@
source = master_branch
return super(BzrBranch5, self).pull(source, overwrite, stop_revision)
+ @needs_write_lock
+ def push(self, target, overwrite=False, stop_revision=None):
+ """Updates branch.push to be bound branch aware."""
+ bound_location = target.get_bound_location()
+ if target.base != bound_location:
+ # not pushing to master, so we need to update master.
+ master_branch = target.get_master_branch()
+ if master_branch:
+ # push into the master from this branch.
+ super(BzrBranch5, self).push(master_branch, overwrite,
+ stop_revision)
+ # and push into the target branch from this. Note that we push from
+ # this branch again, because its considered the highest bandwidth
+ # repository.
+ return super(BzrBranch5, self).push(target, overwrite, stop_revision)
+
def get_bound_location(self):
try:
return self.control_files.get_utf8('bound').read()[:-1]
=== modified file 'bzrlib/builtins.py'
--- a/bzrlib/builtins.py 2007-01-24 17:06:02 +0000
+++ b/bzrlib/builtins.py 2007-01-30 21:06:11 +0000
@@ -676,11 +676,16 @@
except errors.NotLocalUrl:
warning('This transport does not update the working '
'tree of: %s' % (br_to.base,))
- count = br_to.pull(br_from, overwrite)
+ count = br_from.push(br_to, overwrite)
except errors.NoWorkingTree:
- count = br_to.pull(br_from, overwrite)
+ count = br_from.push(br_to, overwrite)
else:
- count = tree_to.pull(br_from, overwrite)
+ tree_to.lock_write()
+ try:
+ count = br_from.push(tree_to.branch, overwrite)
+ tree_to.update()
+ finally:
+ tree_to.unlock()
except errors.DivergedBranches:
raise errors.BzrCommandError('These branches have diverged.'
' Try using "merge" and then "push".')
=== modified file 'bzrlib/errors.py'
--- a/bzrlib/errors.py 2007-01-19 19:23:53 +0000
+++ b/bzrlib/errors.py 2007-01-30 11:52:30 +0000
@@ -405,6 +405,16 @@
self.args = [base] + list(args)
+class UnknownHook(BzrError):
+
+ _fmt = "The %(type)s hook '%(hook)s' is unknown in this version of bzrlib."
+
+ def __init__(self, hook_type, hook_name):
+ BzrError.__init__(self)
+ self.type = hook_type
+ self.hook = hook_name
+
+
class UnsupportedProtocol(PathError):
_fmt = 'Unsupported protocol for url "%(path)s"%(extra)s'
=== modified file 'bzrlib/help_topics.py'
--- a/bzrlib/help_topics.py 2007-01-17 14:46:47 +0000
+++ b/bzrlib/help_topics.py 2007-01-31 16:33:48 +0000
@@ -141,7 +141,7 @@
This does not suppress other plugin effects
--no-plugins Do not process any plugins
---Derror Instead of normal error handling, always print a traceback on
+-Derror Instead of normal error handling, always print a traceback on
error.
--profile Profile execution using the hotshot profiler
--lsprof Profile execution using the lsprof profiler
=== modified file 'bzrlib/lockdir.py'
--- a/bzrlib/lockdir.py 2006-11-10 21:06:11 +0000
+++ b/bzrlib/lockdir.py 2007-01-31 18:49:12 +0000
@@ -220,6 +220,8 @@
self.transport.rename(tmpname, self._held_dir)
self._lock_held = True
self.confirm()
+ except errors.PermissionDenied:
+ raise
except (PathError, DirectoryNotEmpty, FileExists, ResourceBusy), e:
mutter("contention on %r: %s", self, e)
raise LockContention(self)
=== modified file 'bzrlib/merge.py'
--- a/bzrlib/merge.py 2006-11-10 21:06:11 +0000
+++ b/bzrlib/merge.py 2007-01-31 03:51:36 +0000
@@ -572,7 +572,8 @@
parent_id = self.tt.final_parent(trans_id)
if file_id in self.this_tree.inventory:
self.tt.unversion_file(trans_id)
- self.tt.delete_contents(trans_id)
+ if file_id in self.this_tree:
+ self.tt.delete_contents(trans_id)
file_group = self._dump_conflicts(name, parent_id, file_id,
set_version=True)
self._raw_conflicts.append(('contents conflict', file_group))
=== modified file 'bzrlib/osutils.py'
--- a/bzrlib/osutils.py 2007-01-04 23:36:44 +0000
+++ b/bzrlib/osutils.py 2007-02-01 20:36:41 +0000
@@ -40,7 +40,6 @@
from shutil import (
rmtree,
)
-import string
import tempfile
from tempfile import (
mkdtemp,
@@ -777,7 +776,15 @@
def contains_whitespace(s):
"""True if there are any whitespace characters in s."""
- for ch in string.whitespace:
+ # string.whitespace can include '\xa0' in certain locales, because it is
+ # considered "non-breaking-space" as part of ISO-8859-1. But it
+ # 1) Isn't a breaking whitespace
+ # 2) Isn't one of ' \t\r\n' which are characters we sometimes use as
+ # separators
+ # 3) '\xa0' isn't unicode safe since it is >128.
+ # So we are following textwrap's example and hard-coding our own.
+ # We probably could ignore \v and \f, too.
+ for ch in u' \t\n\r\v\f':
if ch in s:
return True
else:
@@ -915,6 +922,19 @@
return sys.platform != "win32"
+def supports_posix_readonly():
+ """Return True if 'readonly' has POSIX semantics, False otherwise.
+
+ Notably, a win32 readonly file cannot be deleted, unlike POSIX where the
+ directory controls creation/deletion, etc.
+
+ And under win32, readonly means that the directory itself cannot be
+ deleted. The contents of a readonly directory can be changed, unlike POSIX
+ where files in readonly directories cannot be added, deleted or renamed.
+ """
+ return sys.platform != "win32"
+
+
def set_or_unset_env(env_variable, value):
"""Modify the environment, setting or removing the env_variable.
=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py 2007-01-19 19:42:19 +0000
+++ b/bzrlib/tests/__init__.py 2007-01-30 10:41:04 +0000
@@ -569,6 +569,12 @@
self._startLogFile()
self._benchcalls = []
self._benchtime = None
+ # prevent hooks affecting tests
+ self._preserved_hooks = bzrlib.branch.Branch.hooks
+ self.addCleanup(self._restoreHooks)
+ # this list of hooks must be kept in sync with the defaults
+ # in branch.py
+ bzrlib.branch.Branch.hooks = bzrlib.branch.BranchHooks()
def _silenceUI(self):
"""Turn off UI for duration of test"""
@@ -835,6 +841,9 @@
for name, value in self.__old_env.iteritems():
osutils.set_or_unset_env(name, value)
+ def _restoreHooks(self):
+ bzrlib.branch.Branch.hooks = self._preserved_hooks
+
def tearDown(self):
self._runCleanups()
unittest.TestCase.tearDown(self)
=== modified file 'bzrlib/tests/branch_implementations/__init__.py'
--- a/bzrlib/tests/branch_implementations/__init__.py 2006-10-11 23:08:27 +0000
+++ b/bzrlib/tests/branch_implementations/__init__.py 2007-02-01 17:18:42 +0000
@@ -42,11 +42,13 @@
'bzrlib.tests.branch_implementations.test_bound_sftp',
'bzrlib.tests.branch_implementations.test_branch',
'bzrlib.tests.branch_implementations.test_break_lock',
+ 'bzrlib.tests.branch_implementations.test_hooks',
'bzrlib.tests.branch_implementations.test_http',
'bzrlib.tests.branch_implementations.test_locking',
'bzrlib.tests.branch_implementations.test_parent',
'bzrlib.tests.branch_implementations.test_permissions',
'bzrlib.tests.branch_implementations.test_pull',
+ 'bzrlib.tests.branch_implementations.test_push',
'bzrlib.tests.branch_implementations.test_update',
]
adapter = BranchTestProviderAdapter(
=== modified file 'bzrlib/tests/branch_implementations/test_bound_sftp.py'
--- a/bzrlib/tests/branch_implementations/test_bound_sftp.py 2007-01-05 17:12:03 +0000
+++ b/bzrlib/tests/branch_implementations/test_bound_sftp.py 2007-01-30 20:58:25 +0000
@@ -184,18 +184,6 @@
self.assertEqual(['r at b-1'], wt_child.branch.revision_history())
self.assertEqual(['r at b-1'], sftp_b_newbase.revision_history())
- def test_pull_updates_both(self):
- b_base, wt_child = self.create_branches()
-
- wt_newchild = b_base.bzrdir.sprout('newchild').open_workingtree()
- open('newchild/b', 'wb').write('newchild b contents\n')
- wt_newchild.commit('newchild', rev_id='r at d-2')
- self.assertEqual(['r at b-1', 'r at d-2'], wt_newchild.branch.revision_history())
-
- wt_child.pull(wt_newchild.branch)
- self.assertEqual(['r at b-1', 'r at d-2'], wt_child.branch.revision_history())
- self.assertEqual(['r at b-1', 'r at d-2'], b_base.revision_history())
-
def test_bind_diverged(self):
from bzrlib.builtins import merge
@@ -333,25 +321,6 @@
self.assertRaises(errors.BoundBranchConnectionFailure,
wt_child.commit, 'added text', rev_id='r at c-2')
- def test_pull_fails(self):
- b_base, wt_child = self.create_branches()
-
- wt_other = wt_child.bzrdir.sprout('other').open_workingtree()
- open('other/a', 'wb').write('new contents\n')
- wt_other.commit('changed a', rev_id='r at d-2')
-
- self.assertEqual(['r at b-1'], b_base.revision_history())
- self.assertEqual(['r at b-1'], wt_child.branch.revision_history())
- self.assertEqual(['r at b-1', 'r at d-2'], wt_other.branch.revision_history())
-
- # this deletes the branch from memory
- del b_base
- # and this moves it out of the way on disk
- os.rename('base', 'hidden_base')
-
- self.assertRaises(errors.BoundBranchConnectionFailure,
- wt_child.pull, wt_other.branch)
-
# TODO: jam 20051231 We need invasive failure tests, so that we can show
# performance even when something fails.
=== modified file 'bzrlib/tests/branch_implementations/test_pull.py'
--- a/bzrlib/tests/branch_implementations/test_pull.py 2006-10-11 23:08:27 +0000
+++ b/bzrlib/tests/branch_implementations/test_pull.py 2007-01-30 20:58:25 +0000
@@ -19,7 +19,7 @@
import os
from bzrlib.branch import Branch
-from bzrlib.osutils import abspath, realpath
+from bzrlib import errors
from bzrlib.tests import TestCaseWithTransport
@@ -53,3 +53,27 @@
parent.commit('merge other', rev_id='P2')
mine.pull(parent.branch)
self.assertEqual(['P1', 'P2'], mine.branch.revision_history())
+
+ def test_pull_updates_checkout_and_master(self):
+ """Pulling into a checkout updates the checkout and the master branch"""
+ master_tree = self.make_branch_and_tree('master')
+ rev1 = master_tree.commit('master')
+ checkout = master_tree.branch.create_checkout('checkout')
+
+ other = master_tree.branch.bzrdir.sprout('other').open_workingtree()
+ rev2 = other.commit('other commit')
+ # now pull, which should update both checkout and master.
+ checkout.branch.pull(other.branch)
+ self.assertEqual([rev1, rev2], checkout.branch.revision_history())
+ self.assertEqual([rev1, rev2], master_tree.branch.revision_history())
+
+ def test_pull_raises_specific_error_on_master_connection_error(self):
+ master_tree = self.make_branch_and_tree('master')
+ checkout = master_tree.branch.create_checkout('checkout')
+ other = master_tree.branch.bzrdir.sprout('other').open_workingtree()
+ # move the branch out of the way on disk to cause a connection
+ # error.
+ os.rename('master', 'master_gone')
+ # try to pull, which should raise a BoundBranchConnectionFailure.
+ self.assertRaises(errors.BoundBranchConnectionFailure,
+ checkout.branch.pull, other.branch)
=== modified file 'bzrlib/tests/test_branch.py'
--- a/bzrlib/tests/test_branch.py 2006-09-07 23:31:28 +0000
+++ b/bzrlib/tests/test_branch.py 2007-01-30 11:52:30 +0000
@@ -32,6 +32,7 @@
BzrDir, BzrDirFormat)
from bzrlib.errors import (NotBranchError,
UnknownFormatError,
+ UnknownHook,
UnsupportedFormatError,
)
@@ -162,3 +163,27 @@
self.assertEqual(made_branch.base, target_branch.base)
opened_branch = branch_dir.open_branch()
self.assertEqual(opened_branch.base, target_branch.base)
+
+
+class TestHooks(TestCase):
+
+ def test_constructor(self):
+ """Check that creating a BranchHooks instance has the right defaults."""
+ hooks = bzrlib.branch.BranchHooks()
+ self.assertTrue("set_rh" in hooks, "set_rh not in %s" % hooks)
+
+ def test_installed_hooks_are_BranchHooks(self):
+ """The installed hooks object should be a BranchHooks."""
+ # the installed hooks are saved in self._preserved_hooks.
+ self.assertIsInstance(self._preserved_hooks, bzrlib.branch.BranchHooks)
+
+ def test_install_hook_raises_unknown_hook(self):
+ """install_hook should raise UnknownHook if a hook is unknown."""
+ hooks = bzrlib.branch.BranchHooks()
+ self.assertRaises(UnknownHook, hooks.install_hook, 'silly', None)
+
+ def test_install_hook_appends_known_hook(self):
+ """install_hook should append the callable for known hooks."""
+ hooks = bzrlib.branch.BranchHooks()
+ hooks.install_hook('set_rh', None)
+ self.assertEqual(hooks['set_rh'], [None])
=== modified file 'bzrlib/tests/test_errors.py'
--- a/bzrlib/tests/test_errors.py 2006-12-21 20:07:34 +0000
+++ b/bzrlib/tests/test_errors.py 2007-01-30 11:52:30 +0000
@@ -94,6 +94,16 @@
"the current request that is open.",
str(error))
+ def test_unknown_hook(self):
+ error = errors.UnknownHook("branch", "foo")
+ self.assertEqualDiff("The branch hook 'foo' is unknown in this version"
+ " of bzrlib.",
+ str(error))
+ error = errors.UnknownHook("tree", "bar")
+ self.assertEqualDiff("The tree hook 'bar' is unknown in this version"
+ " of bzrlib.",
+ str(error))
+
def test_up_to_date(self):
error = errors.UpToDateFormat(bzrdir.BzrDirFormat4())
self.assertEqualDiff("The branch format Bazaar-NG branch, "
=== modified file 'bzrlib/tests/test_lockdir.py'
--- a/bzrlib/tests/test_lockdir.py 2006-09-29 20:12:58 +0000
+++ b/bzrlib/tests/test_lockdir.py 2007-02-01 14:59:04 +0000
@@ -17,13 +17,16 @@
"""Tests for LockDir"""
from cStringIO import StringIO
+import os
from threading import Thread, Lock
import time
import bzrlib
from bzrlib import (
config,
+ errors,
osutils,
+ tests,
)
from bzrlib.errors import (
LockBreakMismatch,
@@ -600,3 +603,12 @@
ld1.create()
ld1.lock_write()
ld1.unlock()
+
+ def test_lock_permission(self):
+ if not osutils.supports_posix_readonly():
+ raise tests.TestSkipped('Cannot induce a permission failure')
+ ld1 = self.get_lock()
+ lock_path = ld1.transport.local_abspath('test_lock')
+ os.mkdir(lock_path)
+ osutils.make_readonly(lock_path)
+ self.assertRaises(errors.PermissionDenied, ld1.attempt_lock)
=== modified file 'bzrlib/tests/test_merge.py'
--- a/bzrlib/tests/test_merge.py 2006-10-11 23:08:27 +0000
+++ b/bzrlib/tests/test_merge.py 2007-01-31 03:51:36 +0000
@@ -173,3 +173,16 @@
conflicts.DeletingParent('Not deleting', 'b', 'b-id'),
conflicts.UnversionedParent('Versioned directory', 'b', 'b-id')],
tree_a.conflicts())
+
+ def test_merge_with_missing(self):
+ tree_a = self.make_branch_and_tree('tree_a')
+ self.build_tree_contents([('tree_a/file', 'content_1')])
+ tree_a.add('file')
+ tree_a.commit('commit base')
+ base_tree = tree_a.basis_tree()
+ tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
+ self.build_tree_contents([('tree_a/file', 'content_2')])
+ tree_a.commit('commit other')
+ other_tree = tree_a.basis_tree()
+ os.unlink('tree_b/file')
+ merge_inner(tree_b.branch, other_tree, base_tree, this_tree=tree_b)
=== modified file 'bzrlib/tests/test_osutils.py'
--- a/bzrlib/tests/test_osutils.py 2007-01-04 23:36:44 +0000
+++ b/bzrlib/tests/test_osutils.py 2007-02-01 14:49:53 +0000
@@ -38,6 +38,20 @@
class TestOSUtils(TestCaseInTempDir):
+ def test_contains_whitespace(self):
+ self.failUnless(osutils.contains_whitespace(u' '))
+ self.failUnless(osutils.contains_whitespace(u'hello there'))
+ self.failUnless(osutils.contains_whitespace(u'hellothere\n'))
+ self.failUnless(osutils.contains_whitespace(u'hello\nthere'))
+ self.failUnless(osutils.contains_whitespace(u'hello\rthere'))
+ self.failUnless(osutils.contains_whitespace(u'hello\tthere'))
+
+ # \xa0 is "Non-breaking-space" which on some python locales thinks it
+ # is whitespace, but we do not.
+ self.failIf(osutils.contains_whitespace(u''))
+ self.failIf(osutils.contains_whitespace(u'hellothere'))
+ self.failIf(osutils.contains_whitespace(u'hello\xa0there'))
+
def test_fancy_rename(self):
# This should work everywhere
def rename(a, b):
=== modified file 'bzrlib/tests/test_selftest.py'
--- a/bzrlib/tests/test_selftest.py 2007-01-11 08:45:51 +0000
+++ b/bzrlib/tests/test_selftest.py 2007-01-30 10:41:04 +0000
@@ -852,7 +852,12 @@
self.assertContainsRe(
output_stream.getvalue(),
r"\d+ms/ +\d+ms\n$")
-
+
+ def test_hooks_sanitised(self):
+ """The bzrlib hooks should be sanitised by setUp."""
+ self.assertEqual(bzrlib.branch.BranchHooks(),
+ bzrlib.branch.Branch.hooks)
+
def test__gather_lsprof_in_benchmarks(self):
"""When _gather_lsprof_in_benchmarks is on, accumulate profile data.
=== modified file 'bzrlib/transform.py'
--- a/bzrlib/transform.py 2006-12-07 04:06:34 +0000
+++ b/bzrlib/transform.py 2007-01-31 17:48:55 +0000
@@ -273,8 +273,7 @@
os.unlink(name)
raise
- for segment in contents:
- f.write(segment)
+ f.writelines(contents)
finally:
f.close()
self._set_mode(trans_id, mode_id, S_ISREG)
More information about the bazaar-commits
mailing list