~bzr-pqm/bzr/bzr.dev

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