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
supports_versioned_directories = True
60
def get_format_description(self):
61
"""See WorkingTreeFormat.get_format_description()."""
62
return "Working tree format 2"
64
def _stub_initialize_on_transport(self, transport, file_mode):
65
"""Workaround: create control files for a remote working tree.
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).
72
inv = inventory.Inventory()
73
xml5.serializer_v5.write_inventory(inv, sio, working=True)
75
transport.put_file('inventory', sio, file_mode)
76
transport.put_bytes('pending-merges', '', file_mode)
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:
86
branch = a_bzrdir.open_branch()
87
if revision_id is None:
88
revision_id = _mod_revision.ensure_null(branch.last_revision())
91
branch.generate_revision_history(revision_id)
94
inv = inventory.Inventory()
95
wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
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):
109
parent_trees = [(revision_id, basis_tree)]
110
wt.set_parent_trees(parent_trees)
111
transform.build_tree(basis_tree, wt)
115
super(WorkingTreeFormat2, self).__init__()
116
from bzrlib.plugins.weave_fmt.bzrdir import BzrDirFormat6
117
self._matchingbzrdir = BzrDirFormat6()
119
def open(self, a_bzrdir, _found=False):
120
"""Return the WorkingTree object for a_bzrdir
122
_found is a private parameter, do not use it. It is used to indicate
123
if format probing has already been done.
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('.'),
134
_control_files=a_bzrdir.open_branch().control_files)
138
class WorkingTree2(InventoryWorkingTree):
139
"""This is the Format 2 working tree.
141
This was the first weave based working tree.
142
- uses os locks for locking.
143
- uses the branch last-revision.
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.
152
# Newer WorkingTree's should only have self._inventory set when they
154
if self._inventory is None:
155
self.read_working_inventory()
157
def _get_check_refs(self):
158
"""Return the references needed to perform a check of this tree."""
159
return [('trees', self.last_revision())]
161
def lock_tree_write(self):
162
"""See WorkingTree.lock_tree_write().
164
In Format2 WorkingTrees we have a single lock for the branch and tree
165
so lock_tree_write() degrades to lock_write().
167
:return: An object with an unlock method which will release the lock
170
self.branch.lock_write()
172
self._control_files.lock_write()
179
# we share control files:
180
if self._control_files._lock_count == 3:
181
# do non-implementation specific cleanup
183
# _inventory_is_modified is always False during a read lock.
184
if self._inventory_is_modified:
186
self._write_hashcache_if_dirty()
188
# reverse order of locking.
190
return self._control_files.unlock()
194
def _iter_conflicts(self):
196
for info in self.list_files():
198
stem = get_conflicted_stem(path)
201
if stem not in conflicted:
207
conflicts = _mod_conflicts.ConflictList()
208
for conflicted in self._iter_conflicts():
211
if osutils.file_kind(self.abspath(conflicted)) != "file":
213
except errors.NoSuchFile:
216
for suffix in ('.THIS', '.OTHER'):
218
kind = osutils.file_kind(self.abspath(conflicted+suffix))
221
except errors.NoSuchFile:
225
ctype = {True: 'text conflict', False: 'contents conflict'}[text]
226
conflicts.append(_mod_conflicts.Conflict.factory(ctype,
228
file_id=self.path2id(conflicted)))
231
def set_conflicts(self, arg):
232
raise errors.UnsupportedOperation(self.set_conflicts, self)
234
def add_conflicts(self, arg):
235
raise errors.UnsupportedOperation(self.add_conflicts, self)