~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: John Arbash Meinel
  • Author(s): Mark Hammond
  • Date: 2008-09-09 17:02:21 UTC
  • mto: This revision was merged to the branch mainline in revision 3697.
  • Revision ID: john@arbash-meinel.com-20080909170221-svim3jw2mrz0amp3
An updated transparent icon for bzr.

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 __future__ import absolute_import
20
 
 
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.mutabletree import MutableTree
34
 
from bzrlib.transport.local import LocalTransport
35
 
from bzrlib.workingtree import (
36
 
    WorkingTreeFormat,
37
 
    )
38
 
from bzrlib.workingtree_3 import (
39
 
    PreDirStateWorkingTree,
40
 
    )
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
 
 
63
 
    supports_versioned_directories = True
64
 
 
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)
108
 
        if basis_tree.get_root_id() is not None:
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)
117
 
        for hook in MutableTree.hooks['post_build_tree']:
118
 
            hook(wt)
119
 
        return wt
120
 
 
121
 
    def __init__(self):
122
 
        super(WorkingTreeFormat2, self).__init__()
123
 
        from bzrlib.plugins.weave_fmt.bzrdir import BzrDirFormat6
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
 
 
145
 
class WorkingTree2(PreDirStateWorkingTree):
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
 
 
153
 
    def __init__(self, basedir, *args, **kwargs):
154
 
        super(WorkingTree2, self).__init__(basedir, *args, **kwargs)
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
 
 
168
 
 
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:
189
 
            # do non-implementation specific cleanup
190
 
            self._cleanup()
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
 
 
239
 
    def set_conflicts(self, arg):
240
 
        raise errors.UnsupportedOperation(self.set_conflicts, self)
241
 
 
242
 
    def add_conflicts(self, arg):
243
 
        raise errors.UnsupportedOperation(self.add_conflicts, self)