1
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
90
85
from bzrlib import symbol_versioning
91
86
from bzrlib.decorators import needs_read_lock, needs_write_lock
92
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, TreeReference
93
87
from bzrlib.lockable_files import LockableFiles
94
88
from bzrlib.lockdir import LockDir
95
89
import bzrlib.mutabletree
96
90
from bzrlib.mutabletree import needs_tree_write_lock
97
91
from bzrlib import osutils
98
92
from bzrlib.osutils import (
111
103
from bzrlib.trace import mutter, note
112
104
from bzrlib.transport.local import LocalTransport
113
105
from bzrlib.progress import DummyProgress, ProgressPhase
114
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
106
from bzrlib.revision import CURRENT_REVISION
115
107
from bzrlib.rio import RioReader, rio_file, Stanza
116
from bzrlib.symbol_versioning import (deprecated_passed,
119
DEPRECATED_PARAMETER,
108
from bzrlib.symbol_versioning import (
110
DEPRECATED_PARAMETER,
123
114
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
290
281
self._control_files.break_lock()
291
282
self.branch.break_lock()
284
def _get_check_refs(self):
285
"""Return the references needed to perform a check of this tree.
287
The default implementation returns no refs, and is only suitable for
288
trees that have no local caching and can commit on ghosts at any time.
290
:seealso: bzrlib.check for details about check_refs.
293
294
def requires_rich_root(self):
294
295
return self._format.requires_rich_root
447
448
def get_file_with_stat(self, file_id, path=None, filtered=True,
448
449
_fstat=os.fstat):
449
"""See MutableTree.get_file_with_stat."""
450
"""See Tree.get_file_with_stat."""
451
452
path = self.id2path(file_id)
452
453
file_obj = self.get_file_byname(path, filtered=False)
453
454
stat_value = _fstat(file_obj.fileno())
454
if self.supports_content_filtering() and filtered:
455
if filtered and self.supports_content_filtering():
455
456
filters = self._content_filter_stack(path)
456
457
file_obj = filtered_input_file(file_obj, filters)
457
458
return (file_obj, stat_value)
462
463
def get_file_byname(self, filename, filtered=True):
463
464
path = self.abspath(filename)
464
465
f = file(path, 'rb')
465
if self.supports_content_filtering() and filtered:
466
if filtered and self.supports_content_filtering():
466
467
filters = self._content_filter_stack(filename)
467
468
return filtered_input_file(f, filters)
487
488
incorrectly attributed to CURRENT_REVISION (but after committing, the
488
489
attribution will be correct).
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(),
491
maybe_file_parent_keys = []
492
for parent_id in self.get_parent_ids():
494
parent_tree = self.revision_tree(parent_id)
495
except errors.NoSuchRevisionInTree:
496
parent_tree = self.branch.repository.revision_tree(parent_id)
497
parent_tree.lock_read()
499
if file_id not in parent_tree:
501
ie = parent_tree.inventory[file_id]
502
if ie.kind != 'file':
503
# Note: this is slightly unnecessary, because symlinks and
504
# directories have a "text" which is the empty text, and we
505
# know that won't mess up annotations. But it seems cleaner
507
parent_text_key = (file_id, ie.revision)
508
if parent_text_key not in maybe_file_parent_keys:
509
maybe_file_parent_keys.append(parent_text_key)
512
graph = _mod_graph.Graph(self.branch.repository.texts)
513
heads = graph.heads(maybe_file_parent_keys)
514
file_parent_keys = []
515
for key in maybe_file_parent_keys:
517
file_parent_keys.append(key)
519
# Now we have the parents of this content
520
annotator = self.branch.repository.texts.get_annotator()
521
text = self.get_file(file_id).read()
522
this_key =(file_id, default_revision)
523
annotator.add_special_text(this_key, file_parent_keys, text)
524
annotations = [(key[-1], line)
525
for key, line in annotator.annotate_flat(this_key)]
516
528
def _get_ancestors(self, default_revision):
517
529
ancestors = set([default_revision])
738
752
kind = _mapper(stat_result.st_mode)
739
753
if kind == 'file':
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(
754
return self._file_content_summary(path, stat_result)
745
755
elif kind == 'directory':
746
756
# perhaps it looks like a plain directory, but it's really a
749
759
kind = 'tree-reference'
750
760
return kind, None, None, None
751
761
elif kind == 'symlink':
752
return ('symlink', None, None,
753
os.readlink(abspath.encode(osutils._fs_enc)
754
).decode(osutils._fs_enc))
762
target = osutils.readlink(abspath)
763
return ('symlink', None, None, target)
756
765
return (kind, None, None, None)
767
def _file_content_summary(self, path, stat_result):
768
size = stat_result.st_size
769
executable = self._is_executable_from_path_and_stat(path, stat_result)
770
# try for a stat cache lookup
771
return ('file', size, executable, self._sha_from_stat(
758
774
def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
759
775
"""Common ghost checking functionality from set_parent_*.
890
906
branch.last_revision().
892
908
from bzrlib.merge import Merger, Merge3Merger
893
pb = bzrlib.ui.ui_factory.nested_progress_bar()
909
pb = ui.ui_factory.nested_progress_bar()
895
911
merger = Merger(self.branch, this_tree=self, pb=pb)
896
912
merger.pp = ProgressPhase("Merge phase", 5, pb)
975
991
def get_symlink_target(self, file_id):
976
return os.readlink(self.id2abspath(file_id).encode(osutils._fs_enc)
977
).decode(osutils._fs_enc)
992
abspath = self.id2abspath(file_id)
993
target = osutils.readlink(abspath)
979
996
@needs_write_lock
980
997
def subsume(self, other_tree):
1081
1098
branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1083
1100
tree_bzrdir = branch_bzrdir
1084
wt = tree_bzrdir.create_workingtree(NULL_REVISION)
1101
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
1085
1102
wt.set_parent_ids(self.get_parent_ids())
1086
1103
my_inv = self.inventory
1087
child_inv = Inventory(root_id=None)
1104
child_inv = inventory.Inventory(root_id=None)
1088
1105
new_root = my_inv[file_id]
1089
1106
my_inv.remove_recursive_id(file_id)
1090
1107
new_root.parent_id = None
1115
1132
def _kind(self, relpath):
1116
1133
return osutils.file_kind(self.abspath(relpath))
1118
def list_files(self, include_root=False):
1119
"""Recursively list all files as (path, class, kind, id, entry).
1135
def list_files(self, include_root=False, from_dir=None, recursive=True):
1136
"""List all files as (path, class, kind, id, entry).
1121
1138
Lists, but does not descend into unversioned directories.
1123
1139
This does not include files that have been deleted in this
1140
tree. Skips the control directory.
1126
Skips the control directory.
1142
:param include_root: if True, do not return an entry for the root
1143
:param from_dir: start from this directory or None for the root
1144
:param recursive: whether to recurse into subdirectories or not
1128
1146
# list_files is an iterator, so @needs_read_lock doesn't work properly
1129
1147
# with it. So callers should be careful to always read_lock the tree.
1131
1149
raise errors.ObjectNotLocked(self)
1133
1151
inv = self.inventory
1134
if include_root is True:
1152
if from_dir is None and include_root is True:
1135
1153
yield ('', 'V', 'directory', inv.root.file_id, inv.root)
1136
1154
# Convert these into local objects to save lookup times
1137
1155
pathjoin = osutils.pathjoin
1144
1162
fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
1146
1164
# directory file_id, relative path, absolute path, reverse sorted children
1147
children = os.listdir(self.basedir)
1165
if from_dir is not None:
1166
from_dir_id = inv.path2id(from_dir)
1167
if from_dir_id is None:
1168
# Directory not versioned
1170
from_dir_abspath = pathjoin(self.basedir, from_dir)
1172
from_dir_id = inv.root.file_id
1173
from_dir_abspath = self.basedir
1174
children = os.listdir(from_dir_abspath)
1148
1175
children.sort()
1149
1176
# jam 20060527 The kernel sized tree seems equivalent whether we
1150
1177
# use a deque and popleft to keep them sorted, or if we use a plain
1151
1178
# list and just reverse() them.
1152
1179
children = collections.deque(children)
1153
stack = [(inv.root.file_id, u'', self.basedir, children)]
1180
stack = [(from_dir_id, u'', from_dir_abspath, children)]
1155
1182
from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
1214
1241
if fk != 'directory':
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
1244
# But do this child first if recursing down
1246
new_children = os.listdir(fap)
1248
new_children = collections.deque(new_children)
1249
stack.append((f_ie.file_id, fp, fap, new_children))
1250
# Break out of inner loop,
1251
# so that we start outer loop with child
1226
1254
# if we finished all children, pop it off the stack
1405
1433
inv = self.inventory
1406
1434
for entry in moved:
1408
self._move_entry(_RenameEntry(entry.to_rel, entry.from_id,
1436
self._move_entry(WorkingTree._RenameEntry(
1437
entry.to_rel, entry.from_id,
1409
1438
entry.to_tail, entry.to_parent_id, entry.from_rel,
1410
1439
entry.from_tail, entry.from_parent_id,
1411
1440
entry.only_change_inv))
1462
1491
from_tail = splitpath(from_rel)[-1]
1463
1492
from_id = inv.path2id(from_rel)
1464
1493
if from_id is None:
1465
raise errors.BzrRenameFailedError(from_rel,to_rel,
1466
errors.NotVersionedError(path=str(from_rel)))
1467
from_entry = inv[from_id]
1494
# if file is missing in the inventory maybe it's in the basis_tree
1495
basis_tree = self.branch.basis_tree()
1496
from_id = basis_tree.path2id(from_rel)
1498
raise errors.BzrRenameFailedError(from_rel,to_rel,
1499
errors.NotVersionedError(path=str(from_rel)))
1500
# put entry back in the inventory so we can rename it
1501
from_entry = basis_tree.inventory[from_id].copy()
1504
from_entry = inv[from_id]
1468
1505
from_parent_id = from_entry.parent_id
1469
1506
to_dir, to_tail = os.path.split(to_rel)
1470
1507
to_dir_id = inv.path2id(to_dir)
1562
1599
@needs_write_lock
1563
1600
def pull(self, source, overwrite=False, stop_revision=None,
1564
change_reporter=None, possible_transports=None):
1565
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1601
change_reporter=None, possible_transports=None, local=False):
1602
top_pb = ui.ui_factory.nested_progress_bar()
1566
1603
source.lock_read()
1568
1605
pp = ProgressPhase("Pull phase", 2, top_pb)
1570
1607
old_revision_info = self.branch.last_revision_info()
1571
1608
basis_tree = self.basis_tree()
1572
1609
count = self.branch.pull(source, overwrite, stop_revision,
1573
possible_transports=possible_transports)
1610
possible_transports=possible_transports,
1574
1612
new_revision_info = self.branch.last_revision_info()
1575
1613
if new_revision_info != old_revision_info:
1576
1614
pp.next_phase()
1577
1615
repository = self.branch.repository
1578
pb = bzrlib.ui.ui_factory.nested_progress_bar()
1616
pb = ui.ui_factory.nested_progress_bar()
1579
1617
basis_tree.lock_read()
1581
1619
new_basis_tree = self.branch.basis_tree()
1860
1898
firstline = xml.split('\n', 1)[0]
1861
1899
if (not 'revision_id="' in firstline or
1862
1900
'format="7"' not in firstline):
1863
inv = self.branch.repository.deserialise_inventory(
1901
inv = self.branch.repository._serializer.read_inventory_from_string(
1865
1903
xml = self._create_basis_xml_from_inventory(new_revision, inv)
1866
1904
self._write_basis_inventory(xml)
1867
1905
except (errors.NoSuchRevision, errors.RevisionNotPresent):
2373
2410
bzrdir_loc = bisect_left(cur_disk_dir_content,
2374
2411
('.bzr', '.bzr'))
2375
2412
if (bzrdir_loc < len(cur_disk_dir_content)
2376
and cur_disk_dir_content[bzrdir_loc][0] == '.bzr'):
2413
and self.bzrdir.is_control_filename(
2414
cur_disk_dir_content[bzrdir_loc][0])):
2377
2415
# we dont yield the contents of, or, .bzr itself.
2378
2416
del cur_disk_dir_content[bzrdir_loc]
2379
2417
if inv_finished:
2513
2551
return un_resolved, resolved
2515
2553
@needs_read_lock
2554
def _check(self, references):
2555
"""Check the tree for consistency.
2557
:param references: A dict with keys matching the items returned by
2558
self._get_check_refs(), and values from looking those keys up in
2517
2561
tree_basis = self.basis_tree()
2518
2562
tree_basis.lock_read()
2520
repo_basis = self.branch.repository.revision_tree(
2521
self.last_revision())
2564
repo_basis = references[('trees', self.last_revision())]
2522
2565
if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2523
2566
raise errors.BzrCheckError(
2524
2567
"Mismatched basis inventory content.")
2570
2613
if self._inventory is None:
2571
2614
self.read_working_inventory()
2616
def _get_check_refs(self):
2617
"""Return the references needed to perform a check of this tree."""
2618
return [('trees', self.last_revision())]
2573
2620
def lock_tree_write(self):
2574
2621
"""See WorkingTree.lock_tree_write().
2622
2669
def _change_last_revision(self, revision_id):
2623
2670
"""See WorkingTree._change_last_revision."""
2624
if revision_id is None or revision_id == NULL_REVISION:
2671
if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
2626
2673
self._transport.delete('last-revision')
2627
2674
except errors.NoSuchFile:
2632
2679
mode=self.bzrdir._get_file_mode())
2682
def _get_check_refs(self):
2683
"""Return the references needed to perform a check of this tree."""
2684
return [('trees', self.last_revision())]
2635
2686
@needs_tree_write_lock
2636
2687
def set_conflicts(self, conflicts):
2637
2688
self._put_rio('conflicts', conflicts.to_stanzas(),
2936
2987
# only set an explicit root id if there is one to set.
2937
2988
if basis_tree.inventory.root is not None:
2938
2989
wt.set_root_id(basis_tree.get_root_id())
2939
if revision_id == NULL_REVISION:
2990
if revision_id == _mod_revision.NULL_REVISION:
2940
2991
wt.set_parent_trees([])
2942
2993
wt.set_parent_trees([(revision_id, basis_tree)])
2984
3035
return self.get_format_string()
2987
__default_format = WorkingTreeFormat4()
3038
__default_format = WorkingTreeFormat6()
2988
3039
WorkingTreeFormat.register_format(__default_format)
2989
WorkingTreeFormat.register_format(WorkingTreeFormat6())
2990
3040
WorkingTreeFormat.register_format(WorkingTreeFormat5())
3041
WorkingTreeFormat.register_format(WorkingTreeFormat4())
2991
3042
WorkingTreeFormat.register_format(WorkingTreeFormat3())
2992
3043
WorkingTreeFormat.set_default_format(__default_format)
2993
3044
# formats which have no format string are not discoverable