1
# Copyright (C) 2005-2010 Canonical Ltd
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.
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.
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
17
"""Weave-era working tree objects."""
19
from cStringIO import StringIO
22
conflicts as _mod_conflicts,
26
revision as _mod_revision,
30
from bzrlib.decorators import needs_read_lock
31
from bzrlib.transport.local import LocalTransport
32
from bzrlib.workingtree import (
35
from bzrlib.workingtree_3 import (
36
PreDirStateWorkingTree,
40
def get_conflicted_stem(path):
41
for suffix in _mod_conflicts.CONFLICT_SUFFIXES:
42
if path.endswith(suffix):
43
return path[:-len(suffix)]
46
class WorkingTreeFormat2(WorkingTreeFormat):
47
"""The second working tree format.
49
This format modified the hash cache from the format 1 hash cache.
52
upgrade_recommended = True
54
requires_normalized_unicode_filenames = True
56
case_sensitive_filename = "Branch-FoRMaT"
58
missing_parent_conflicts = False
60
supports_versioned_directories = True
62
def get_format_description(self):
63
"""See WorkingTreeFormat.get_format_description()."""
64
return "Working tree format 2"
66
def _stub_initialize_on_transport(self, transport, file_mode):
67
"""Workaround: create control files for a remote working tree.
69
This ensures that it can later be updated and dealt with locally,
70
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
71
no working tree. (See bug #43064).
74
inv = inventory.Inventory()
75
xml5.serializer_v5.write_inventory(inv, sio, working=True)
77
transport.put_file('inventory', sio, file_mode)
78
transport.put_bytes('pending-merges', '', file_mode)
80
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
81
accelerator_tree=None, hardlink=False):
82
"""See WorkingTreeFormat.initialize()."""
83
if not isinstance(a_bzrdir.transport, LocalTransport):
84
raise errors.NotLocalUrl(a_bzrdir.transport.base)
85
if from_branch is not None:
88
branch = a_bzrdir.open_branch()
89
if revision_id is None:
90
revision_id = _mod_revision.ensure_null(branch.last_revision())
93
branch.generate_revision_history(revision_id)
96
inv = inventory.Inventory()
97
wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
103
_control_files=branch.control_files)
104
basis_tree = branch.repository.revision_tree(revision_id)
105
if basis_tree.inventory.root is not None:
106
wt.set_root_id(basis_tree.get_root_id())
107
# set the parent list and cache the basis tree.
108
if _mod_revision.is_null(revision_id):
111
parent_trees = [(revision_id, basis_tree)]
112
wt.set_parent_trees(parent_trees)
113
transform.build_tree(basis_tree, wt)
117
super(WorkingTreeFormat2, self).__init__()
118
from bzrlib.plugins.weave_fmt.bzrdir import BzrDirFormat6
119
self._matchingbzrdir = BzrDirFormat6()
121
def open(self, a_bzrdir, _found=False):
122
"""Return the WorkingTree object for a_bzrdir
124
_found is a private parameter, do not use it. It is used to indicate
125
if format probing has already been done.
128
# we are being called directly and must probe.
129
raise NotImplementedError
130
if not isinstance(a_bzrdir.transport, LocalTransport):
131
raise errors.NotLocalUrl(a_bzrdir.transport.base)
132
wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
136
_control_files=a_bzrdir.open_branch().control_files)
140
class WorkingTree2(PreDirStateWorkingTree):
141
"""This is the Format 2 working tree.
143
This was the first weave based working tree.
144
- uses os locks for locking.
145
- uses the branch last-revision.
148
def __init__(self, basedir, *args, **kwargs):
149
super(WorkingTree2, self).__init__(basedir, *args, **kwargs)
150
# WorkingTree2 has more of a constraint that self._inventory must
151
# exist. Because this is an older format, we don't mind the overhead
152
# caused by the extra computation here.
154
# Newer WorkingTree's should only have self._inventory set when they
156
if self._inventory is None:
157
self.read_working_inventory()
159
def _get_check_refs(self):
160
"""Return the references needed to perform a check of this tree."""
161
return [('trees', self.last_revision())]
164
def lock_tree_write(self):
165
"""See WorkingTree.lock_tree_write().
167
In Format2 WorkingTrees we have a single lock for the branch and tree
168
so lock_tree_write() degrades to lock_write().
170
:return: An object with an unlock method which will release the lock
173
self.branch.lock_write()
175
self._control_files.lock_write()
182
# we share control files:
183
if self._control_files._lock_count == 3:
184
# do non-implementation specific cleanup
186
# _inventory_is_modified is always False during a read lock.
187
if self._inventory_is_modified:
189
self._write_hashcache_if_dirty()
191
# reverse order of locking.
193
return self._control_files.unlock()
197
def _iter_conflicts(self):
199
for info in self.list_files():
201
stem = get_conflicted_stem(path)
204
if stem not in conflicted:
210
conflicts = _mod_conflicts.ConflictList()
211
for conflicted in self._iter_conflicts():
214
if osutils.file_kind(self.abspath(conflicted)) != "file":
216
except errors.NoSuchFile:
219
for suffix in ('.THIS', '.OTHER'):
221
kind = osutils.file_kind(self.abspath(conflicted+suffix))
224
except errors.NoSuchFile:
228
ctype = {True: 'text conflict', False: 'contents conflict'}[text]
229
conflicts.append(_mod_conflicts.Conflict.factory(ctype,
231
file_id=self.path2id(conflicted)))
234
def set_conflicts(self, arg):
235
raise errors.UnsupportedOperation(self.set_conflicts, self)
237
def add_conflicts(self, arg):
238
raise errors.UnsupportedOperation(self.add_conflicts, self)