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 (
38
def get_conflicted_stem(path):
39
for suffix in _mod_conflicts.CONFLICT_SUFFIXES:
40
if path.endswith(suffix):
41
return path[:-len(suffix)]
44
class WorkingTreeFormat2(WorkingTreeFormat):
45
"""The second working tree format.
47
This format modified the hash cache from the format 1 hash cache.
50
upgrade_recommended = True
52
requires_normalized_unicode_filenames = True
54
case_sensitive_filename = "Branch-FoRMaT"
56
missing_parent_conflicts = False
58
def get_format_description(self):
59
"""See WorkingTreeFormat.get_format_description()."""
60
return "Working tree format 2"
62
def _stub_initialize_on_transport(self, transport, file_mode):
63
"""Workaround: create control files for a remote working tree.
65
This ensures that it can later be updated and dealt with locally,
66
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
67
no working tree. (See bug #43064).
70
inv = inventory.Inventory()
71
xml5.serializer_v5.write_inventory(inv, sio, working=True)
73
transport.put_file('inventory', sio, file_mode)
74
transport.put_bytes('pending-merges', '', file_mode)
76
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
77
accelerator_tree=None, hardlink=False):
78
"""See WorkingTreeFormat.initialize()."""
79
if not isinstance(a_bzrdir.transport, LocalTransport):
80
raise errors.NotLocalUrl(a_bzrdir.transport.base)
81
if from_branch is not None:
84
branch = a_bzrdir.open_branch()
85
if revision_id is None:
86
revision_id = _mod_revision.ensure_null(branch.last_revision())
89
branch.generate_revision_history(revision_id)
92
inv = inventory.Inventory()
93
wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
99
_control_files=branch.control_files)
100
basis_tree = branch.repository.revision_tree(revision_id)
101
if basis_tree.inventory.root is not None:
102
wt.set_root_id(basis_tree.get_root_id())
103
# set the parent list and cache the basis tree.
104
if _mod_revision.is_null(revision_id):
107
parent_trees = [(revision_id, basis_tree)]
108
wt.set_parent_trees(parent_trees)
109
transform.build_tree(basis_tree, wt)
113
super(WorkingTreeFormat2, self).__init__()
114
from bzrlib.plugins.weave_fmt.bzrdir import BzrDirFormat6
115
self._matchingbzrdir = BzrDirFormat6()
117
def open(self, a_bzrdir, _found=False):
118
"""Return the WorkingTree object for a_bzrdir
120
_found is a private parameter, do not use it. It is used to indicate
121
if format probing has already been done.
124
# we are being called directly and must probe.
125
raise NotImplementedError
126
if not isinstance(a_bzrdir.transport, LocalTransport):
127
raise errors.NotLocalUrl(a_bzrdir.transport.base)
128
wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
132
_control_files=a_bzrdir.open_branch().control_files)
136
class WorkingTree2(WorkingTree):
137
"""This is the Format 2 working tree.
139
This was the first weave based working tree.
140
- uses os locks for locking.
141
- uses the branch last-revision.
144
def __init__(self, *args, **kwargs):
145
super(WorkingTree2, self).__init__(*args, **kwargs)
146
# WorkingTree2 has more of a constraint that self._inventory must
147
# exist. Because this is an older format, we don't mind the overhead
148
# caused by the extra computation here.
150
# Newer WorkingTree's should only have self._inventory set when they
152
if self._inventory is None:
153
self.read_working_inventory()
155
def _get_check_refs(self):
156
"""Return the references needed to perform a check of this tree."""
157
return [('trees', self.last_revision())]
159
def lock_tree_write(self):
160
"""See WorkingTree.lock_tree_write().
162
In Format2 WorkingTrees we have a single lock for the branch and tree
163
so lock_tree_write() degrades to lock_write().
165
:return: An object with an unlock method which will release the lock
168
self.branch.lock_write()
170
self._control_files.lock_write()
177
# do non-implementation specific cleanup
180
# we share control files:
181
if self._control_files._lock_count == 3:
182
# _inventory_is_modified is always False during a read lock.
183
if self._inventory_is_modified:
185
self._write_hashcache_if_dirty()
187
# reverse order of locking.
189
return self._control_files.unlock()
193
def _iter_conflicts(self):
195
for info in self.list_files():
197
stem = get_conflicted_stem(path)
200
if stem not in conflicted:
206
conflicts = _mod_conflicts.ConflictList()
207
for conflicted in self._iter_conflicts():
210
if osutils.file_kind(self.abspath(conflicted)) != "file":
212
except errors.NoSuchFile:
215
for suffix in ('.THIS', '.OTHER'):
217
kind = osutils.file_kind(self.abspath(conflicted+suffix))
220
except errors.NoSuchFile:
224
ctype = {True: 'text conflict', False: 'contents conflict'}[text]
225
conflicts.append(_mod_conflicts.Conflict.factory(ctype,
227
file_id=self.path2id(conflicted)))