~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/plugins/weave_fmt/workingtree.py

  • Committer: Jelmer Vernooij
  • Date: 2011-03-05 01:37:14 UTC
  • mfrom: (5582.12.6 weave-plugin)
  • mto: This revision was merged to the branch mainline in revision 5718.
  • Revision ID: jelmer@samba.org-20110305013714-mtsd852bf0jq11sp
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-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
 
"""Weave-era working tree objects."""
18
 
 
19
 
from cStringIO import StringIO
20
 
 
21
 
from bzrlib import (
22
 
    conflicts as _mod_conflicts,
23
 
    errors,
24
 
    inventory,
25
 
    osutils,
26
 
    revision as _mod_revision,
27
 
    transform,
28
 
    xml5,
29
 
    )
30
 
from bzrlib.decorators import needs_read_lock
31
 
from bzrlib.transport.local import LocalTransport
32
 
from bzrlib.workingtree import (
33
 
    WorkingTreeFormat,
34
 
    WorkingTree,
35
 
    )
36
 
 
37
 
 
38
 
def get_conflicted_stem(path):
39
 
    for suffix in _mod_conflicts.CONFLICT_SUFFIXES:
40
 
        if path.endswith(suffix):
41
 
            return path[:-len(suffix)]
42
 
 
43
 
 
44
 
class WorkingTreeFormat2(WorkingTreeFormat):
45
 
    """The second working tree format.
46
 
 
47
 
    This format modified the hash cache from the format 1 hash cache.
48
 
    """
49
 
 
50
 
    upgrade_recommended = True
51
 
 
52
 
    requires_normalized_unicode_filenames = True
53
 
 
54
 
    case_sensitive_filename = "Branch-FoRMaT"
55
 
 
56
 
    missing_parent_conflicts = False
57
 
 
58
 
    def get_format_description(self):
59
 
        """See WorkingTreeFormat.get_format_description()."""
60
 
        return "Working tree format 2"
61
 
 
62
 
    def _stub_initialize_on_transport(self, transport, file_mode):
63
 
        """Workaround: create control files for a remote working tree.
64
 
 
65
 
        This ensures that it can later be updated and dealt with locally,
66
 
        since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
67
 
        no working tree.  (See bug #43064).
68
 
        """
69
 
        sio = StringIO()
70
 
        inv = inventory.Inventory()
71
 
        xml5.serializer_v5.write_inventory(inv, sio, working=True)
72
 
        sio.seek(0)
73
 
        transport.put_file('inventory', sio, file_mode)
74
 
        transport.put_bytes('pending-merges', '', file_mode)
75
 
 
76
 
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
77
 
                   accelerator_tree=None, hardlink=False):
78
 
        """See WorkingTreeFormat.initialize()."""
79
 
        if not isinstance(a_bzrdir.transport, LocalTransport):
80
 
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
81
 
        if from_branch is not None:
82
 
            branch = from_branch
83
 
        else:
84
 
            branch = a_bzrdir.open_branch()
85
 
        if revision_id is None:
86
 
            revision_id = _mod_revision.ensure_null(branch.last_revision())
87
 
        branch.lock_write()
88
 
        try:
89
 
            branch.generate_revision_history(revision_id)
90
 
        finally:
91
 
            branch.unlock()
92
 
        inv = inventory.Inventory()
93
 
        wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
94
 
                         branch,
95
 
                         inv,
96
 
                         _internal=True,
97
 
                         _format=self,
98
 
                         _bzrdir=a_bzrdir,
99
 
                         _control_files=branch.control_files)
100
 
        basis_tree = branch.repository.revision_tree(revision_id)
101
 
        if basis_tree.inventory.root is not None:
102
 
            wt.set_root_id(basis_tree.get_root_id())
103
 
        # set the parent list and cache the basis tree.
104
 
        if _mod_revision.is_null(revision_id):
105
 
            parent_trees = []
106
 
        else:
107
 
            parent_trees = [(revision_id, basis_tree)]
108
 
        wt.set_parent_trees(parent_trees)
109
 
        transform.build_tree(basis_tree, wt)
110
 
        return wt
111
 
 
112
 
    def __init__(self):
113
 
        super(WorkingTreeFormat2, self).__init__()
114
 
        from bzrlib.plugins.weave_fmt.bzrdir import BzrDirFormat6
115
 
        self._matchingbzrdir = BzrDirFormat6()
116
 
 
117
 
    def open(self, a_bzrdir, _found=False):
118
 
        """Return the WorkingTree object for a_bzrdir
119
 
 
120
 
        _found is a private parameter, do not use it. It is used to indicate
121
 
               if format probing has already been done.
122
 
        """
123
 
        if not _found:
124
 
            # we are being called directly and must probe.
125
 
            raise NotImplementedError
126
 
        if not isinstance(a_bzrdir.transport, LocalTransport):
127
 
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
128
 
        wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
129
 
                           _internal=True,
130
 
                           _format=self,
131
 
                           _bzrdir=a_bzrdir,
132
 
                           _control_files=a_bzrdir.open_branch().control_files)
133
 
        return wt
134
 
 
135
 
 
136
 
class WorkingTree2(WorkingTree):
137
 
    """This is the Format 2 working tree.
138
 
 
139
 
    This was the first weave based working tree.
140
 
     - uses os locks for locking.
141
 
     - uses the branch last-revision.
142
 
    """
143
 
 
144
 
    def __init__(self, *args, **kwargs):
145
 
        super(WorkingTree2, self).__init__(*args, **kwargs)
146
 
        # WorkingTree2 has more of a constraint that self._inventory must
147
 
        # exist. Because this is an older format, we don't mind the overhead
148
 
        # caused by the extra computation here.
149
 
 
150
 
        # Newer WorkingTree's should only have self._inventory set when they
151
 
        # have a read lock.
152
 
        if self._inventory is None:
153
 
            self.read_working_inventory()
154
 
 
155
 
    def _get_check_refs(self):
156
 
        """Return the references needed to perform a check of this tree."""
157
 
        return [('trees', self.last_revision())]
158
 
 
159
 
    def lock_tree_write(self):
160
 
        """See WorkingTree.lock_tree_write().
161
 
 
162
 
        In Format2 WorkingTrees we have a single lock for the branch and tree
163
 
        so lock_tree_write() degrades to lock_write().
164
 
 
165
 
        :return: An object with an unlock method which will release the lock
166
 
            obtained.
167
 
        """
168
 
        self.branch.lock_write()
169
 
        try:
170
 
            self._control_files.lock_write()
171
 
            return self
172
 
        except:
173
 
            self.branch.unlock()
174
 
            raise
175
 
 
176
 
    def unlock(self):
177
 
        # do non-implementation specific cleanup
178
 
        self._cleanup()
179
 
 
180
 
        # we share control files:
181
 
        if self._control_files._lock_count == 3:
182
 
            # _inventory_is_modified is always False during a read lock.
183
 
            if self._inventory_is_modified:
184
 
                self.flush()
185
 
            self._write_hashcache_if_dirty()
186
 
 
187
 
        # reverse order of locking.
188
 
        try:
189
 
            return self._control_files.unlock()
190
 
        finally:
191
 
            self.branch.unlock()
192
 
 
193
 
    def _iter_conflicts(self):
194
 
        conflicted = set()
195
 
        for info in self.list_files():
196
 
            path = info[0]
197
 
            stem = get_conflicted_stem(path)
198
 
            if stem is None:
199
 
                continue
200
 
            if stem not in conflicted:
201
 
                conflicted.add(stem)
202
 
                yield stem
203
 
 
204
 
    @needs_read_lock
205
 
    def conflicts(self):
206
 
        conflicts = _mod_conflicts.ConflictList()
207
 
        for conflicted in self._iter_conflicts():
208
 
            text = True
209
 
            try:
210
 
                if osutils.file_kind(self.abspath(conflicted)) != "file":
211
 
                    text = False
212
 
            except errors.NoSuchFile:
213
 
                text = False
214
 
            if text is True:
215
 
                for suffix in ('.THIS', '.OTHER'):
216
 
                    try:
217
 
                        kind = osutils.file_kind(self.abspath(conflicted+suffix))
218
 
                        if kind != "file":
219
 
                            text = False
220
 
                    except errors.NoSuchFile:
221
 
                        text = False
222
 
                    if text == False:
223
 
                        break
224
 
            ctype = {True: 'text conflict', False: 'contents conflict'}[text]
225
 
            conflicts.append(_mod_conflicts.Conflict.factory(ctype,
226
 
                             path=conflicted,
227
 
                             file_id=self.path2id(conflicted)))
228
 
        return conflicts
229
 
 
230