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