84
90
from bzrlib import symbol_versioning
85
91
from bzrlib.decorators import needs_read_lock, needs_write_lock
92
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, TreeReference
86
93
from bzrlib.lockable_files import LockableFiles
87
94
from bzrlib.lockdir import LockDir
88
95
import bzrlib.mutabletree
89
96
from bzrlib.mutabletree import needs_tree_write_lock
90
97
from bzrlib import osutils
91
98
from bzrlib.osutils import (
101
110
from bzrlib.filters import filtered_input_file
102
111
from bzrlib.trace import mutter, note
103
112
from bzrlib.transport.local import LocalTransport
104
from bzrlib.progress import ProgressPhase
105
from bzrlib.revision import CURRENT_REVISION
113
from bzrlib.progress import DummyProgress, ProgressPhase
114
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
106
115
from bzrlib.rio import RioReader, rio_file, Stanza
107
from bzrlib.symbol_versioning import (
109
DEPRECATED_PARAMETER,
116
from bzrlib.symbol_versioning import (deprecated_passed,
119
DEPRECATED_PARAMETER,
113
123
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
114
# TODO: Modifying the conflict objects or their type is currently nearly
115
# impossible as there is no clear relationship between the working tree format
116
# and the conflict list file format.
117
124
CONFLICT_HEADER_1 = "BZR conflict list format 1"
119
126
ERROR_PATH_NOT_FOUND = 3 # WindowsError errno code, equivalent to ENOENT
283
290
self._control_files.break_lock()
284
291
self.branch.break_lock()
286
def _get_check_refs(self):
287
"""Return the references needed to perform a check of this tree.
289
The default implementation returns no refs, and is only suitable for
290
trees that have no local caching and can commit on ghosts at any time.
292
:seealso: bzrlib.check for details about check_refs.
296
293
def requires_rich_root(self):
297
294
return self._format.requires_rich_root
454
451
path = self.id2path(file_id)
455
452
file_obj = self.get_file_byname(path, filtered=False)
456
453
stat_value = _fstat(file_obj.fileno())
457
if filtered and self.supports_content_filtering():
454
if self.supports_content_filtering() and filtered:
458
455
filters = self._content_filter_stack(path)
459
456
file_obj = filtered_input_file(file_obj, filters)
460
457
return (file_obj, stat_value)
490
487
incorrectly attributed to CURRENT_REVISION (but after committing, the
491
488
attribution will be correct).
493
maybe_file_parent_keys = []
494
for parent_id in self.get_parent_ids():
496
parent_tree = self.revision_tree(parent_id)
497
except errors.NoSuchRevisionInTree:
498
parent_tree = self.branch.repository.revision_tree(parent_id)
499
parent_tree.lock_read()
501
if file_id not in parent_tree:
503
ie = parent_tree.inventory[file_id]
504
if ie.kind != 'file':
505
# Note: this is slightly unnecessary, because symlinks and
506
# directories have a "text" which is the empty text, and we
507
# know that won't mess up annotations. But it seems cleaner
509
parent_text_key = (file_id, ie.revision)
510
if parent_text_key not in maybe_file_parent_keys:
511
maybe_file_parent_keys.append(parent_text_key)
514
graph = _mod_graph.Graph(self.branch.repository.texts)
515
heads = graph.heads(maybe_file_parent_keys)
516
file_parent_keys = []
517
for key in maybe_file_parent_keys:
519
file_parent_keys.append(key)
521
# Now we have the parents of this content
522
annotator = self.branch.repository.texts.get_annotator()
523
text = self.get_file(file_id).read()
524
this_key =(file_id, default_revision)
525
annotator.add_special_text(this_key, file_parent_keys, text)
526
annotations = [(key[-1], line)
527
for key, line in annotator.annotate_flat(this_key)]
490
basis = self.basis_tree()
493
changes = self.iter_changes(basis, True, [self.id2path(file_id)],
494
require_versioned=True).next()
495
changed_content, kind = changes[2], changes[6]
496
if not changed_content:
497
return basis.annotate_iter(file_id)
501
if kind[0] != 'file':
504
old_lines = list(basis.annotate_iter(file_id))
506
for tree in self.branch.repository.revision_trees(
507
self.get_parent_ids()[1:]):
508
if file_id not in tree:
510
old.append(list(tree.annotate_iter(file_id)))
511
return annotate.reannotate(old, self.get_file(file_id).readlines(),
530
516
def _get_ancestors(self, default_revision):
531
517
ancestors = set([default_revision])
758
738
kind = _mapper(stat_result.st_mode)
759
739
if kind == 'file':
760
return self._file_content_summary(path, stat_result)
740
size = stat_result.st_size
741
# try for a stat cache lookup
742
executable = self._is_executable_from_path_and_stat(path, stat_result)
743
return (kind, size, executable, self._sha_from_stat(
761
745
elif kind == 'directory':
762
746
# perhaps it looks like a plain directory, but it's really a
771
755
return (kind, None, None, None)
773
def _file_content_summary(self, path, stat_result):
774
size = stat_result.st_size
775
executable = self._is_executable_from_path_and_stat(path, stat_result)
776
# try for a stat cache lookup
777
return ('file', size, executable, self._sha_from_stat(
780
757
def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
781
758
"""Common ghost checking functionality from set_parent_*.
912
889
branch.last_revision().
914
891
from bzrlib.merge import Merger, Merge3Merger
915
merger = Merger(self.branch, this_tree=self)
916
# check that there are no local alterations
917
if not force and self.has_changes():
918
raise errors.UncommittedChanges(self)
919
if to_revision is None:
920
to_revision = _mod_revision.ensure_null(branch.last_revision())
921
merger.other_rev_id = to_revision
922
if _mod_revision.is_null(merger.other_rev_id):
923
raise errors.NoCommits(branch)
924
self.branch.fetch(branch, last_revision=merger.other_rev_id)
925
merger.other_basis = merger.other_rev_id
926
merger.other_tree = self.branch.repository.revision_tree(
928
merger.other_branch = branch
929
if from_revision is None:
932
merger.set_base_revision(from_revision, branch)
933
if merger.base_rev_id == merger.other_rev_id:
934
raise errors.PointlessMerge
935
merger.backup_files = False
936
if merge_type is None:
937
merger.merge_type = Merge3Merger
939
merger.merge_type = merge_type
940
merger.set_interesting_files(None)
941
merger.show_base = False
942
merger.reprocess = False
943
conflicts = merger.do_merge()
892
pb = bzrlib.ui.ui_factory.nested_progress_bar()
894
merger = Merger(self.branch, this_tree=self, pb=pb)
895
merger.pp = ProgressPhase("Merge phase", 5, pb)
896
merger.pp.next_phase()
897
# check that there are no
899
merger.check_basis(check_clean=True, require_commits=False)
900
if to_revision is None:
901
to_revision = _mod_revision.ensure_null(branch.last_revision())
902
merger.other_rev_id = to_revision
903
if _mod_revision.is_null(merger.other_rev_id):
904
raise errors.NoCommits(branch)
905
self.branch.fetch(branch, last_revision=merger.other_rev_id)
906
merger.other_basis = merger.other_rev_id
907
merger.other_tree = self.branch.repository.revision_tree(
909
merger.other_branch = branch
910
merger.pp.next_phase()
911
if from_revision is None:
914
merger.set_base_revision(from_revision, branch)
915
if merger.base_rev_id == merger.other_rev_id:
916
raise errors.PointlessMerge
917
merger.backup_files = False
918
if merge_type is None:
919
merger.merge_type = Merge3Merger
921
merger.merge_type = merge_type
922
merger.set_interesting_files(None)
923
merger.show_base = False
924
merger.reprocess = False
925
conflicts = merger.do_merge()
1097
1081
branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1099
1083
tree_bzrdir = branch_bzrdir
1100
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
1084
wt = tree_bzrdir.create_workingtree(NULL_REVISION)
1101
1085
wt.set_parent_ids(self.get_parent_ids())
1102
1086
my_inv = self.inventory
1103
child_inv = inventory.Inventory(root_id=None)
1087
child_inv = Inventory(root_id=None)
1104
1088
new_root = my_inv[file_id]
1105
1089
my_inv.remove_recursive_id(file_id)
1106
1090
new_root.parent_id = None
1131
1115
def _kind(self, relpath):
1132
1116
return osutils.file_kind(self.abspath(relpath))
1134
def list_files(self, include_root=False, from_dir=None, recursive=True):
1135
"""List all files as (path, class, kind, id, entry).
1118
def list_files(self, include_root=False):
1119
"""Recursively list all files as (path, class, kind, id, entry).
1137
1121
Lists, but does not descend into unversioned directories.
1138
1123
This does not include files that have been deleted in this
1139
tree. Skips the control directory.
1141
:param include_root: if True, do not return an entry for the root
1142
:param from_dir: start from this directory or None for the root
1143
:param recursive: whether to recurse into subdirectories or not
1126
Skips the control directory.
1145
1128
# list_files is an iterator, so @needs_read_lock doesn't work properly
1146
1129
# with it. So callers should be careful to always read_lock the tree.
1161
1144
fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
1163
1146
# directory file_id, relative path, absolute path, reverse sorted children
1164
if from_dir is not None:
1165
from_dir_id = inv.path2id(from_dir)
1166
if from_dir_id is None:
1167
# Directory not versioned
1169
from_dir_abspath = pathjoin(self.basedir, from_dir)
1171
from_dir_id = inv.root.file_id
1172
from_dir_abspath = self.basedir
1173
children = os.listdir(from_dir_abspath)
1147
children = os.listdir(self.basedir)
1174
1148
children.sort()
1175
1149
# jam 20060527 The kernel sized tree seems equivalent whether we
1176
1150
# use a deque and popleft to keep them sorted, or if we use a plain
1177
1151
# list and just reverse() them.
1178
1152
children = collections.deque(children)
1179
stack = [(from_dir_id, u'', from_dir_abspath, children)]
1153
stack = [(inv.root.file_id, u'', self.basedir, children)]
1181
1155
from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
1240
1214
if fk != 'directory':
1243
# But do this child first if recursing down
1245
new_children = os.listdir(fap)
1247
new_children = collections.deque(new_children)
1248
stack.append((f_ie.file_id, fp, fap, new_children))
1249
# Break out of inner loop,
1250
# so that we start outer loop with child
1217
# But do this child first
1218
new_children = os.listdir(fap)
1220
new_children = collections.deque(new_children)
1221
stack.append((f_ie.file_id, fp, fap, new_children))
1222
# Break out of inner loop,
1223
# so that we start outer loop with child
1253
1226
# if we finished all children, pop it off the stack
1432
1405
inv = self.inventory
1433
1406
for entry in moved:
1435
self._move_entry(WorkingTree._RenameEntry(
1436
entry.to_rel, entry.from_id,
1408
self._move_entry(_RenameEntry(entry.to_rel, entry.from_id,
1437
1409
entry.to_tail, entry.to_parent_id, entry.from_rel,
1438
1410
entry.from_tail, entry.from_parent_id,
1439
1411
entry.only_change_inv))
1490
1462
from_tail = splitpath(from_rel)[-1]
1491
1463
from_id = inv.path2id(from_rel)
1492
1464
if from_id is None:
1493
# if file is missing in the inventory maybe it's in the basis_tree
1494
basis_tree = self.branch.basis_tree()
1495
from_id = basis_tree.path2id(from_rel)
1497
raise errors.BzrRenameFailedError(from_rel,to_rel,
1498
errors.NotVersionedError(path=str(from_rel)))
1499
# put entry back in the inventory so we can rename it
1500
from_entry = basis_tree.inventory[from_id].copy()
1503
from_entry = inv[from_id]
1465
raise errors.BzrRenameFailedError(from_rel,to_rel,
1466
errors.NotVersionedError(path=str(from_rel)))
1467
from_entry = inv[from_id]
1504
1468
from_parent_id = from_entry.parent_id
1505
1469
to_dir, to_tail = os.path.split(to_rel)
1506
1470
to_dir_id = inv.path2id(to_dir)
1598
1562
@needs_write_lock
1599
1563
def pull(self, source, overwrite=False, stop_revision=None,
1600
1564
change_reporter=None, possible_transports=None, local=False):
1565
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1601
1566
source.lock_read()
1568
pp = ProgressPhase("Pull phase", 2, top_pb)
1603
1570
old_revision_info = self.branch.last_revision_info()
1604
1571
basis_tree = self.basis_tree()
1605
1572
count = self.branch.pull(source, overwrite, stop_revision,
1616
1585
new_basis_tree,
1618
1587
this_tree=self,
1620
1589
change_reporter=change_reporter)
1621
basis_root_id = basis_tree.get_root_id()
1622
new_root_id = new_basis_tree.get_root_id()
1623
if basis_root_id != new_root_id:
1624
self.set_root_id(new_root_id)
1590
if (basis_tree.inventory.root is None and
1591
new_basis_tree.inventory.root is not None):
1592
self.set_root_id(new_basis_tree.get_root_id())
1626
1595
basis_tree.unlock()
1627
1596
# TODO - dedup parents list with things merged by pull ?
1628
1597
# reuse the revisiontree we merged against to set the new
1731
1701
r"""Check whether the filename matches an ignore pattern.
1733
1703
Patterns containing '/' or '\' need to match the whole path;
1734
others match against only the last component. Patterns starting
1735
with '!' are ignore exceptions. Exceptions take precedence
1736
over regular patterns and cause the filename to not be ignored.
1704
others match against only the last component.
1738
1706
If the file is ignored, returns the pattern which caused it to
1739
1707
be ignored, otherwise None. So this can simply be used as a
1740
1708
boolean if desired."""
1741
1709
if getattr(self, '_ignoreglobster', None) is None:
1742
self._ignoreglobster = globbing.ExceptionGlobster(self.get_ignore_list())
1710
self._ignoreglobster = globbing.Globster(self.get_ignore_list())
1743
1711
return self._ignoreglobster.match(filename)
1745
1713
def kind(self, file_id):
1893
1857
# revision_id is set. We must check for this full string, because a
1894
1858
# root node id can legitimately look like 'revision_id' but cannot
1895
1859
# contain a '"'.
1896
xml = self.branch.repository._get_inventory_xml(new_revision)
1860
xml = self.branch.repository.get_inventory_xml(new_revision)
1897
1861
firstline = xml.split('\n', 1)[0]
1898
1862
if (not 'revision_id="' in firstline or
1899
1863
'format="7"' not in firstline):
1900
inv = self.branch.repository._serializer.read_inventory_from_string(
1864
inv = self.branch.repository.deserialise_inventory(
1902
1866
xml = self._create_basis_xml_from_inventory(new_revision, inv)
1903
1867
self._write_basis_inventory(xml)
1904
1868
except (errors.NoSuchRevision, errors.RevisionNotPresent):
2024
1982
new_status = 'I'
2026
1984
new_status = '?'
2027
# XXX: Really should be a more abstract reporter interface
2028
kind_ch = osutils.kind_marker(self.kind(fid))
2029
to_file.write(new_status + ' ' + f + kind_ch + '\n')
1985
textui.show_status(new_status, self.kind(fid), f,
2030
1987
# Unversion file
2031
1988
inv_delta.append((f, None, fid, None))
2032
1989
message = "removed %s" % (f,)
2184
2142
raise NotImplementedError(self.unlock)
2188
def update(self, change_reporter=None, possible_transports=None,
2189
revision=None, old_tip=_marker):
2144
def update(self, change_reporter=None, possible_transports=None):
2190
2145
"""Update a working tree along its branch.
2192
2147
This will update the branch if its bound too, which means we have
2210
2165
- Merge current state -> basis tree of the master w.r.t. the old tree
2212
2167
- Do a 'normal' merge of the old branch basis if it is relevant.
2214
:param revision: The target revision to update to. Must be in the
2216
:param old_tip: If branch.update() has already been run, the value it
2217
returned (old tip of the branch or None). _marker is used
2220
2169
if self.branch.get_bound_location() is not None:
2221
2170
self.lock_write()
2222
update_branch = (old_tip is self._marker)
2171
update_branch = True
2224
2173
self.lock_tree_write()
2225
2174
update_branch = False
2227
2176
if update_branch:
2228
2177
old_tip = self.branch.update(possible_transports)
2230
if old_tip is self._marker:
2232
return self._update_tree(old_tip, change_reporter, revision)
2180
return self._update_tree(old_tip, change_reporter)
2236
2184
@needs_tree_write_lock
2237
def _update_tree(self, old_tip=None, change_reporter=None, revision=None):
2185
def _update_tree(self, old_tip=None, change_reporter=None):
2238
2186
"""Update a tree to the master branch.
2240
2188
:param old_tip: if supplied, the previous tip revision the branch,
2250
2198
# We MUST save it even if an error occurs, because otherwise the users
2251
2199
# local work is unreferenced and will appear to have been lost.
2255
2203
last_rev = self.get_parent_ids()[0]
2256
2204
except IndexError:
2257
2205
last_rev = _mod_revision.NULL_REVISION
2258
if revision is None:
2259
revision = self.branch.last_revision()
2261
if revision not in self.branch.revision_history():
2262
raise errors.NoSuchRevision(self.branch, revision)
2264
old_tip = old_tip or _mod_revision.NULL_REVISION
2266
if not _mod_revision.is_null(old_tip) and old_tip != last_rev:
2267
# the branch we are bound to was updated
2268
# merge those changes in first
2269
base_tree = self.basis_tree()
2270
other_tree = self.branch.repository.revision_tree(old_tip)
2271
nb_conflicts = merge.merge_inner(self.branch, other_tree,
2272
base_tree, this_tree=self,
2273
change_reporter=change_reporter)
2275
self.add_parent_tree((old_tip, other_tree))
2276
trace.note('Rerun update after fixing the conflicts.')
2279
if last_rev != _mod_revision.ensure_null(revision):
2280
# the working tree is up to date with the branch
2281
# we can merge the specified revision from master
2282
to_tree = self.branch.repository.revision_tree(revision)
2283
to_root_id = to_tree.get_root_id()
2206
if last_rev != _mod_revision.ensure_null(self.branch.last_revision()):
2207
# merge tree state up to new branch tip.
2285
2208
basis = self.basis_tree()
2286
2209
basis.lock_read()
2288
if (basis.inventory.root is None
2289
or basis.inventory.root.file_id != to_root_id):
2290
self.set_root_id(to_root_id)
2211
to_tree = self.branch.basis_tree()
2212
if basis.inventory.root is None:
2213
self.set_root_id(to_tree.get_root_id())
2215
result += merge.merge_inner(
2220
change_reporter=change_reporter)
2295
# determine the branch point
2296
graph = self.branch.repository.get_graph()
2297
base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
2299
base_tree = self.branch.repository.revision_tree(base_rev_id)
2301
nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
2303
change_reporter=change_reporter)
2304
self.set_last_revision(revision)
2305
2223
# TODO - dedup parents list with things merged by pull ?
2306
2224
# reuse the tree we've updated to to set the basis:
2307
parent_trees = [(revision, to_tree)]
2225
parent_trees = [(self.branch.last_revision(), to_tree)]
2308
2226
merges = self.get_parent_ids()[1:]
2309
2227
# Ideally we ask the tree for the trees here, that way the working
2310
2228
# tree can decide whether to give us the entire tree or give us a
2314
2232
for parent in merges:
2315
2233
parent_trees.append(
2316
2234
(parent, self.branch.repository.revision_tree(parent)))
2317
if not _mod_revision.is_null(old_tip):
2235
if (old_tip is not None and not _mod_revision.is_null(old_tip)):
2318
2236
parent_trees.append(
2319
2237
(old_tip, self.branch.repository.revision_tree(old_tip)))
2320
2238
self.set_parent_trees(parent_trees)
2321
2239
last_rev = parent_trees[0][0]
2241
# the working tree had the same last-revision as the master
2242
# branch did. We may still have pivot local work from the local
2243
# branch into old_tip:
2244
if (old_tip is not None and not _mod_revision.is_null(old_tip)):
2245
self.add_parent_tree_id(old_tip)
2246
if (old_tip is not None and not _mod_revision.is_null(old_tip)
2247
and old_tip != last_rev):
2248
# our last revision was not the prior branch last revision
2249
# and we have converted that last revision to a pending merge.
2250
# base is somewhere between the branch tip now
2251
# and the now pending merge
2253
# Since we just modified the working tree and inventory, flush out
2254
# the current state, before we modify it again.
2255
# TODO: jam 20070214 WorkingTree3 doesn't require this, dirstate
2256
# requires it only because TreeTransform directly munges the
2257
# inventory and calls tree._write_inventory(). Ultimately we
2258
# should be able to remove this extra flush.
2260
graph = self.branch.repository.get_graph()
2261
base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
2263
base_tree = self.branch.repository.revision_tree(base_rev_id)
2264
other_tree = self.branch.repository.revision_tree(old_tip)
2265
result += merge.merge_inner(
2270
change_reporter=change_reporter)
2324
2273
def _write_hashcache_if_dirty(self):
2325
2274
"""Write out the hashcache if it is dirty."""
2566
2515
return un_resolved, resolved
2568
2517
@needs_read_lock
2569
def _check(self, references):
2570
"""Check the tree for consistency.
2572
:param references: A dict with keys matching the items returned by
2573
self._get_check_refs(), and values from looking those keys up in
2576
2519
tree_basis = self.basis_tree()
2577
2520
tree_basis.lock_read()
2579
repo_basis = references[('trees', self.last_revision())]
2522
repo_basis = self.branch.repository.revision_tree(
2523
self.last_revision())
2580
2524
if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2581
2525
raise errors.BzrCheckError(
2582
2526
"Mismatched basis inventory content.")
2693
2634
mode=self.bzrdir._get_file_mode())
2696
def _get_check_refs(self):
2697
"""Return the references needed to perform a check of this tree."""
2698
return [('trees', self.last_revision())]
2700
2637
@needs_tree_write_lock
2701
2638
def set_conflicts(self, conflicts):
2702
2639
self._put_rio('conflicts', conflicts.to_stanzas(),
3049
2986
return self.get_format_string()
3052
__default_format = WorkingTreeFormat6()
2989
__default_format = WorkingTreeFormat4()
3053
2990
WorkingTreeFormat.register_format(__default_format)
2991
WorkingTreeFormat.register_format(WorkingTreeFormat6())
3054
2992
WorkingTreeFormat.register_format(WorkingTreeFormat5())
3055
WorkingTreeFormat.register_format(WorkingTreeFormat4())
3056
2993
WorkingTreeFormat.register_format(WorkingTreeFormat3())
3057
2994
WorkingTreeFormat.set_default_format(__default_format)
3058
2995
# formats which have no format string are not discoverable