~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Vincent Ladeuil
  • Date: 2011-07-06 09:22:00 UTC
  • mfrom: (6008 +trunk)
  • mto: (6012.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 6013.
  • Revision ID: v.ladeuil+lp@free.fr-20110706092200-7iai2mwzc0sqdsvf
MergingĀ inĀ trunk

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