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 __future__ import absolute_import
21
from cStringIO import StringIO
24
conflicts as _mod_conflicts,
28
revision as _mod_revision,
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 (
38
from bzrlib.workingtree_3 import (
39
PreDirStateWorkingTree,
43
def get_conflicted_stem(path):
44
for suffix in _mod_conflicts.CONFLICT_SUFFIXES:
45
if path.endswith(suffix):
46
return path[:-len(suffix)]
49
class WorkingTreeFormat2(WorkingTreeFormat):
50
"""The second working tree format.
52
This format modified the hash cache from the format 1 hash cache.
55
upgrade_recommended = True
57
requires_normalized_unicode_filenames = True
59
case_sensitive_filename = "Branch-FoRMaT"
61
missing_parent_conflicts = False
63
supports_versioned_directories = True
65
def get_format_description(self):
66
"""See WorkingTreeFormat.get_format_description()."""
67
return "Working tree format 2"
69
def _stub_initialize_on_transport(self, transport, file_mode):
70
"""Workaround: create control files for a remote working tree.
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).
77
inv = inventory.Inventory()
78
xml5.serializer_v5.write_inventory(inv, sio, working=True)
80
transport.put_file('inventory', sio, file_mode)
81
transport.put_bytes('pending-merges', '', file_mode)
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:
91
branch = a_bzrdir.open_branch()
92
if revision_id is None:
93
revision_id = _mod_revision.ensure_null(branch.last_revision())
96
branch.generate_revision_history(revision_id)
99
inv = inventory.Inventory()
100
wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
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):
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']:
122
super(WorkingTreeFormat2, self).__init__()
123
from bzrlib.plugins.weave_fmt.bzrdir import BzrDirFormat6
124
self._matchingbzrdir = BzrDirFormat6()
126
def open(self, a_bzrdir, _found=False):
127
"""Return the WorkingTree object for a_bzrdir
129
_found is a private parameter, do not use it. It is used to indicate
130
if format probing has already been done.
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('.'),
141
_control_files=a_bzrdir.open_branch().control_files)
145
class WorkingTree2(PreDirStateWorkingTree):
146
"""This is the Format 2 working tree.
148
This was the first weave based working tree.
149
- uses os locks for locking.
150
- uses the branch last-revision.
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.
159
# Newer WorkingTree's should only have self._inventory set when they
161
if self._inventory is None:
162
self.read_working_inventory()
164
def _get_check_refs(self):
165
"""Return the references needed to perform a check of this tree."""
166
return [('trees', self.last_revision())]
169
def lock_tree_write(self):
170
"""See WorkingTree.lock_tree_write().
172
In Format2 WorkingTrees we have a single lock for the branch and tree
173
so lock_tree_write() degrades to lock_write().
175
:return: An object with an unlock method which will release the lock
178
self.branch.lock_write()
180
self._control_files.lock_write()
187
# we share control files:
188
if self._control_files._lock_count == 3:
189
# do non-implementation specific cleanup
191
# _inventory_is_modified is always False during a read lock.
192
if self._inventory_is_modified:
194
self._write_hashcache_if_dirty()
196
# reverse order of locking.
198
return self._control_files.unlock()
202
def _iter_conflicts(self):
204
for info in self.list_files():
206
stem = get_conflicted_stem(path)
209
if stem not in conflicted:
215
conflicts = _mod_conflicts.ConflictList()
216
for conflicted in self._iter_conflicts():
219
if osutils.file_kind(self.abspath(conflicted)) != "file":
221
except errors.NoSuchFile:
224
for suffix in ('.THIS', '.OTHER'):
226
kind = osutils.file_kind(self.abspath(conflicted+suffix))
229
except errors.NoSuchFile:
233
ctype = {True: 'text conflict', False: 'contents conflict'}[text]
234
conflicts.append(_mod_conflicts.Conflict.factory(ctype,
236
file_id=self.path2id(conflicted)))
239
def set_conflicts(self, arg):
240
raise errors.UnsupportedOperation(self.set_conflicts, self)
242
def add_conflicts(self, arg):
243
raise errors.UnsupportedOperation(self.add_conflicts, self)