/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/switch.py

  • Committer: Robert Collins
  • Date: 2010-07-04 06:22:11 UTC
  • mto: This revision was merged to the branch mainline in revision 5332.
  • Revision ID: robertc@robertcollins.net-20100704062211-tk9hw6bnsn5x47fm
``bzrlib.lsprof.profile`` will no longer silently generate bad threaded
profiles when concurrent profile requests are made. Instead the profile
requests will be serialised. Reentrant requests will now deadlock.
(Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2007, 2009, 2010 Canonical Ltd.
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
# Original author: David Allouche
 
18
 
 
19
from bzrlib import errors, merge, revision
 
20
from bzrlib.branch import Branch
 
21
from bzrlib.trace import note
 
22
 
 
23
 
 
24
def _run_post_switch_hooks(control_dir, to_branch, force, revision_id):
 
25
    from bzrlib.branch import SwitchHookParams
 
26
    hooks = Branch.hooks['post_switch']
 
27
    if not hooks:
 
28
        return
 
29
    params = SwitchHookParams(control_dir, to_branch, force, revision_id)
 
30
    for hook in hooks:
 
31
        hook(params)
 
32
 
 
33
def switch(control_dir, to_branch, force=False, quiet=False, revision_id=None):
 
34
    """Switch the branch associated with a checkout.
 
35
 
 
36
    :param control_dir: BzrDir of the checkout to change
 
37
    :param to_branch: branch that the checkout is to reference
 
38
    :param force: skip the check for local commits in a heavy checkout
 
39
    :param revision_id: revision ID to switch to.
 
40
    """
 
41
    _check_pending_merges(control_dir, force)
 
42
    try:
 
43
        source_repository = control_dir.open_branch().repository
 
44
    except errors.NotBranchError:
 
45
        source_repository = to_branch.repository
 
46
    _set_branch_location(control_dir, to_branch, force)
 
47
    tree = control_dir.open_workingtree()
 
48
    _update(tree, source_repository, quiet, revision_id)
 
49
    _run_post_switch_hooks(control_dir, to_branch, force, revision_id)
 
50
 
 
51
def _check_pending_merges(control, force=False):
 
52
    """Check that there are no outstanding pending merges before switching.
 
53
 
 
54
    :param control: BzrDir of the branch to check
 
55
    """
 
56
    try:
 
57
        tree = control.open_workingtree()
 
58
    except errors.NotBranchError, ex:
 
59
        # Lightweight checkout and branch is no longer there
 
60
        if force:
 
61
            return
 
62
        else:
 
63
            raise ex
 
64
    # XXX: Should the tree be locked for get_parent_ids?
 
65
    existing_pending_merges = tree.get_parent_ids()[1:]
 
66
    if len(existing_pending_merges) > 0:
 
67
        raise errors.BzrCommandError('Pending merges must be '
 
68
            'committed or reverted before using switch.')
 
69
 
 
70
 
 
71
def _set_branch_location(control, to_branch, force=False):
 
72
    """Set location value of a branch reference.
 
73
 
 
74
    :param control: BzrDir of the checkout to change
 
75
    :param to_branch: branch that the checkout is to reference
 
76
    :param force: skip the check for local commits in a heavy checkout
 
77
    """
 
78
    branch_format = control.find_branch_format()
 
79
    if branch_format.get_reference(control) is not None:
 
80
        # Lightweight checkout: update the branch reference
 
81
        branch_format.set_reference(control, None, to_branch)
 
82
    else:
 
83
        b = control.open_branch()
 
84
        bound_branch = b.get_bound_location()
 
85
        if bound_branch is not None:
 
86
            # Heavyweight checkout: check all local commits
 
87
            # have been pushed to the current bound branch then
 
88
            # synchronise the local branch with the new remote branch
 
89
            # and bind to it
 
90
            possible_transports = []
 
91
            try:
 
92
                if not force and _any_local_commits(b, possible_transports):
 
93
                    raise errors.BzrCommandError(
 
94
                        'Cannot switch as local commits found in the checkout. '
 
95
                        'Commit these to the bound branch or use --force to '
 
96
                        'throw them away.')
 
97
            except errors.BoundBranchConnectionFailure, e:
 
98
                raise errors.BzrCommandError(
 
99
                        'Unable to connect to current master branch %(target)s: '
 
100
                        '%(error)s To switch anyway, use --force.' %
 
101
                        e.__dict__)
 
102
            b.set_bound_location(None)
 
103
            b.pull(to_branch, overwrite=True,
 
104
                possible_transports=possible_transports)
 
105
            b.set_bound_location(to_branch.base)
 
106
        else:
 
107
            raise errors.BzrCommandError('Cannot switch a branch, '
 
108
                'only a checkout.')
 
109
 
 
110
 
 
111
def _any_local_commits(this_branch, possible_transports):
 
112
    """Does this branch have any commits not in the master branch?"""
 
113
    last_rev = revision.ensure_null(this_branch.last_revision())
 
114
    if last_rev != revision.NULL_REVISION:
 
115
        other_branch = this_branch.get_master_branch(possible_transports)
 
116
        this_branch.lock_read()
 
117
        other_branch.lock_read()
 
118
        try:
 
119
            other_last_rev = other_branch.last_revision()
 
120
            graph = this_branch.repository.get_graph(
 
121
                other_branch.repository)
 
122
            if not graph.is_ancestor(last_rev, other_last_rev):
 
123
                return True
 
124
        finally:
 
125
            other_branch.unlock()
 
126
            this_branch.unlock()
 
127
    return False
 
128
 
 
129
 
 
130
def _update(tree, source_repository, quiet=False, revision_id=None):
 
131
    """Update a working tree to the latest revision of its branch.
 
132
 
 
133
    :param tree: the working tree
 
134
    :param source_repository: repository holding the revisions
 
135
    """
 
136
    tree.lock_tree_write()
 
137
    try:
 
138
        to_branch = tree.branch
 
139
        if revision_id is None:
 
140
            revision_id = to_branch.last_revision()
 
141
        if tree.last_revision() == revision_id:
 
142
            if not quiet:
 
143
                note("Tree is up to date at revision %d.", to_branch.revno())
 
144
            return
 
145
        base_tree = source_repository.revision_tree(tree.last_revision())
 
146
        merge.Merge3Merger(tree, tree, base_tree, to_branch.repository.revision_tree(revision_id))
 
147
        tree.set_last_revision(to_branch.last_revision())
 
148
        if not quiet:
 
149
            note('Updated to revision %d.' % to_branch.revno())
 
150
    finally:
 
151
        tree.unlock()