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"
497
488
incorrectly attributed to CURRENT_REVISION (but after committing, the
498
489
attribution will be correct).
500
basis = self.basis_tree()
503
changes = self.iter_changes(basis, True, [self.id2path(file_id)],
504
require_versioned=True).next()
505
changed_content, kind = changes[2], changes[6]
506
if not changed_content:
507
return basis.annotate_iter(file_id)
511
if kind[0] != 'file':
514
old_lines = list(basis.annotate_iter(file_id))
516
for tree in self.branch.repository.revision_trees(
517
self.get_parent_ids()[1:]):
518
if file_id not in tree:
520
old.append(list(tree.annotate_iter(file_id)))
521
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)]
526
528
def _get_ancestors(self, default_revision):
527
529
ancestors = set([default_revision])
899
901
branch.last_revision().
901
903
from bzrlib.merge import Merger, Merge3Merger
902
pb = bzrlib.ui.ui_factory.nested_progress_bar()
904
pb = ui.ui_factory.nested_progress_bar()
904
906
merger = Merger(self.branch, this_tree=self, pb=pb)
905
907
merger.pp = ProgressPhase("Merge phase", 5, pb)
1091
1093
branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1093
1095
tree_bzrdir = branch_bzrdir
1094
wt = tree_bzrdir.create_workingtree(NULL_REVISION)
1096
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
1095
1097
wt.set_parent_ids(self.get_parent_ids())
1096
1098
my_inv = self.inventory
1097
child_inv = Inventory(root_id=None)
1099
child_inv = inventory.Inventory(root_id=None)
1098
1100
new_root = my_inv[file_id]
1099
1101
my_inv.remove_recursive_id(file_id)
1100
1102
new_root.parent_id = None
1125
1127
def _kind(self, relpath):
1126
1128
return osutils.file_kind(self.abspath(relpath))
1128
def list_files(self, include_root=False):
1129
"""Recursively list all files as (path, class, kind, id, entry).
1130
def list_files(self, include_root=False, from_dir=None, recursive=True):
1131
"""List all files as (path, class, kind, id, entry).
1131
1133
Lists, but does not descend into unversioned directories.
1133
1134
This does not include files that have been deleted in this
1135
tree. Skips the control directory.
1136
Skips the control directory.
1137
:param include_root: if True, do not return an entry for the root
1138
:param from_dir: start from this directory or None for the root
1139
:param recursive: whether to recurse into subdirectories or not
1138
1141
# list_files is an iterator, so @needs_read_lock doesn't work properly
1139
1142
# with it. So callers should be careful to always read_lock the tree.
1141
1144
raise errors.ObjectNotLocked(self)
1143
1146
inv = self.inventory
1144
if include_root is True:
1147
if from_dir is None and include_root is True:
1145
1148
yield ('', 'V', 'directory', inv.root.file_id, inv.root)
1146
1149
# Convert these into local objects to save lookup times
1147
1150
pathjoin = osutils.pathjoin
1154
1157
fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
1156
1159
# directory file_id, relative path, absolute path, reverse sorted children
1157
children = os.listdir(self.basedir)
1160
if from_dir is not None:
1161
from_dir_id = inv.path2id(from_dir)
1162
if from_dir_id is None:
1163
# Directory not versioned
1165
from_dir_abspath = pathjoin(self.basedir, from_dir)
1167
from_dir_id = inv.root.file_id
1168
from_dir_abspath = self.basedir
1169
children = os.listdir(from_dir_abspath)
1158
1170
children.sort()
1159
1171
# jam 20060527 The kernel sized tree seems equivalent whether we
1160
1172
# use a deque and popleft to keep them sorted, or if we use a plain
1161
1173
# list and just reverse() them.
1162
1174
children = collections.deque(children)
1163
stack = [(inv.root.file_id, u'', self.basedir, children)]
1175
stack = [(from_dir_id, u'', from_dir_abspath, children)]
1165
1177
from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
1224
1236
if fk != 'directory':
1227
# But do this child first
1228
new_children = os.listdir(fap)
1230
new_children = collections.deque(new_children)
1231
stack.append((f_ie.file_id, fp, fap, new_children))
1232
# Break out of inner loop,
1233
# so that we start outer loop with child
1239
# But do this child first if recursing down
1241
new_children = os.listdir(fap)
1243
new_children = collections.deque(new_children)
1244
stack.append((f_ie.file_id, fp, fap, new_children))
1245
# Break out of inner loop,
1246
# so that we start outer loop with child
1236
1249
# if we finished all children, pop it off the stack
1415
1428
inv = self.inventory
1416
1429
for entry in moved:
1418
self._move_entry(_RenameEntry(entry.to_rel, entry.from_id,
1431
self._move_entry(WorkingTree._RenameEntry(
1432
entry.to_rel, entry.from_id,
1419
1433
entry.to_tail, entry.to_parent_id, entry.from_rel,
1420
1434
entry.from_tail, entry.from_parent_id,
1421
1435
entry.only_change_inv))
1472
1486
from_tail = splitpath(from_rel)[-1]
1473
1487
from_id = inv.path2id(from_rel)
1474
1488
if from_id is None:
1475
raise errors.BzrRenameFailedError(from_rel,to_rel,
1476
errors.NotVersionedError(path=str(from_rel)))
1477
from_entry = inv[from_id]
1489
# if file is missing in the inventory maybe it's in the basis_tree
1490
basis_tree = self.branch.basis_tree()
1491
from_id = basis_tree.path2id(from_rel)
1493
raise errors.BzrRenameFailedError(from_rel,to_rel,
1494
errors.NotVersionedError(path=str(from_rel)))
1495
# put entry back in the inventory so we can rename it
1496
from_entry = basis_tree.inventory[from_id].copy()
1499
from_entry = inv[from_id]
1478
1500
from_parent_id = from_entry.parent_id
1479
1501
to_dir, to_tail = os.path.split(to_rel)
1480
1502
to_dir_id = inv.path2id(to_dir)
1572
1594
@needs_write_lock
1573
1595
def pull(self, source, overwrite=False, stop_revision=None,
1574
1596
change_reporter=None, possible_transports=None, local=False):
1575
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1597
top_pb = ui.ui_factory.nested_progress_bar()
1576
1598
source.lock_read()
1578
1600
pp = ProgressPhase("Pull phase", 2, top_pb)
2643
2664
def _change_last_revision(self, revision_id):
2644
2665
"""See WorkingTree._change_last_revision."""
2645
if revision_id is None or revision_id == NULL_REVISION:
2666
if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
2647
2668
self._transport.delete('last-revision')
2648
2669
except errors.NoSuchFile:
2961
2982
# only set an explicit root id if there is one to set.
2962
2983
if basis_tree.inventory.root is not None:
2963
2984
wt.set_root_id(basis_tree.get_root_id())
2964
if revision_id == NULL_REVISION:
2985
if revision_id == _mod_revision.NULL_REVISION:
2965
2986
wt.set_parent_trees([])
2967
2988
wt.set_parent_trees([(revision_id, basis_tree)])