1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007, 2008 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
85
90
from bzrlib import symbol_versioning
86
91
from bzrlib.decorators import needs_read_lock, needs_write_lock
92
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, TreeReference
87
93
from bzrlib.lockable_files import LockableFiles
88
94
from bzrlib.lockdir import LockDir
89
95
import bzrlib.mutabletree
90
96
from bzrlib.mutabletree import needs_tree_write_lock
91
97
from bzrlib import osutils
92
98
from bzrlib.osutils import (
103
111
from bzrlib.trace import mutter, note
104
112
from bzrlib.transport.local import LocalTransport
105
113
from bzrlib.progress import DummyProgress, ProgressPhase
106
from bzrlib.revision import CURRENT_REVISION
114
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
107
115
from bzrlib.rio import RioReader, rio_file, Stanza
108
from bzrlib.symbol_versioning import (
110
DEPRECATED_PARAMETER,
116
from bzrlib.symbol_versioning import (deprecated_passed,
119
DEPRECATED_PARAMETER,
114
123
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
442
451
path = self.id2path(file_id)
443
452
file_obj = self.get_file_byname(path, filtered=False)
444
453
stat_value = _fstat(file_obj.fileno())
445
if filtered and self.supports_content_filtering():
454
if self.supports_content_filtering() and filtered:
446
455
filters = self._content_filter_stack(path)
447
456
file_obj = filtered_input_file(file_obj, filters)
448
457
return (file_obj, stat_value)
453
462
def get_file_byname(self, filename, filtered=True):
454
463
path = self.abspath(filename)
455
464
f = file(path, 'rb')
456
if filtered and self.supports_content_filtering():
465
if self.supports_content_filtering() and filtered:
457
466
filters = self._content_filter_stack(filename)
458
467
return filtered_input_file(f, filters)
478
487
incorrectly attributed to CURRENT_REVISION (but after committing, the
479
488
attribution will be correct).
481
maybe_file_parent_keys = []
482
for parent_id in self.get_parent_ids():
484
parent_tree = self.revision_tree(parent_id)
485
except errors.NoSuchRevisionInTree:
486
parent_tree = self.branch.repository.revision_tree(parent_id)
487
parent_tree.lock_read()
489
if file_id not in parent_tree:
491
ie = parent_tree.inventory[file_id]
492
if ie.kind != 'file':
493
# Note: this is slightly unnecessary, because symlinks and
494
# directories have a "text" which is the empty text, and we
495
# know that won't mess up annotations. But it seems cleaner
497
parent_text_key = (file_id, ie.revision)
498
if parent_text_key not in maybe_file_parent_keys:
499
maybe_file_parent_keys.append(parent_text_key)
502
graph = _mod_graph.Graph(self.branch.repository.texts)
503
heads = graph.heads(maybe_file_parent_keys)
504
file_parent_keys = []
505
for key in maybe_file_parent_keys:
507
file_parent_keys.append(key)
509
# Now we have the parents of this content
510
annotator = self.branch.repository.texts.get_annotator()
511
text = self.get_file(file_id).read()
512
this_key =(file_id, default_revision)
513
annotator.add_special_text(this_key, file_parent_keys, text)
514
annotations = [(key[-1], line)
515
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(),
518
516
def _get_ancestors(self, default_revision):
519
517
ancestors = set([default_revision])
891
889
branch.last_revision().
893
891
from bzrlib.merge import Merger, Merge3Merger
894
pb = ui.ui_factory.nested_progress_bar()
892
pb = bzrlib.ui.ui_factory.nested_progress_bar()
896
894
merger = Merger(self.branch, this_tree=self, pb=pb)
897
895
merger.pp = ProgressPhase("Merge phase", 5, pb)
1083
1081
branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1085
1083
tree_bzrdir = branch_bzrdir
1086
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
1084
wt = tree_bzrdir.create_workingtree(NULL_REVISION)
1087
1085
wt.set_parent_ids(self.get_parent_ids())
1088
1086
my_inv = self.inventory
1089
child_inv = inventory.Inventory(root_id=None)
1087
child_inv = Inventory(root_id=None)
1090
1088
new_root = my_inv[file_id]
1091
1089
my_inv.remove_recursive_id(file_id)
1092
1090
new_root.parent_id = None
1117
1115
def _kind(self, relpath):
1118
1116
return osutils.file_kind(self.abspath(relpath))
1120
def list_files(self, include_root=False, from_dir=None, recursive=True):
1121
"""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).
1123
1121
Lists, but does not descend into unversioned directories.
1124
1123
This does not include files that have been deleted in this
1125
tree. Skips the control directory.
1127
:param include_root: if True, do not return an entry for the root
1128
:param from_dir: start from this directory or None for the root
1129
:param recursive: whether to recurse into subdirectories or not
1126
Skips the control directory.
1131
1128
# list_files is an iterator, so @needs_read_lock doesn't work properly
1132
1129
# with it. So callers should be careful to always read_lock the tree.
1134
1131
raise errors.ObjectNotLocked(self)
1136
1133
inv = self.inventory
1137
if from_dir is None and include_root is True:
1134
if include_root is True:
1138
1135
yield ('', 'V', 'directory', inv.root.file_id, inv.root)
1139
1136
# Convert these into local objects to save lookup times
1140
1137
pathjoin = osutils.pathjoin
1147
1144
fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
1149
1146
# directory file_id, relative path, absolute path, reverse sorted children
1150
if from_dir is not None:
1151
from_dir_id = inv.path2id(from_dir)
1152
if from_dir_id is None:
1153
# Directory not versioned
1155
from_dir_abspath = pathjoin(self.basedir, from_dir)
1157
from_dir_id = inv.root.file_id
1158
from_dir_abspath = self.basedir
1159
children = os.listdir(from_dir_abspath)
1147
children = os.listdir(self.basedir)
1160
1148
children.sort()
1161
1149
# jam 20060527 The kernel sized tree seems equivalent whether we
1162
1150
# use a deque and popleft to keep them sorted, or if we use a plain
1163
1151
# list and just reverse() them.
1164
1152
children = collections.deque(children)
1165
stack = [(from_dir_id, u'', from_dir_abspath, children)]
1153
stack = [(inv.root.file_id, u'', self.basedir, children)]
1167
1155
from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
1226
1214
if fk != 'directory':
1229
# But do this child first if recursing down
1231
new_children = os.listdir(fap)
1233
new_children = collections.deque(new_children)
1234
stack.append((f_ie.file_id, fp, fap, new_children))
1235
# Break out of inner loop,
1236
# 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
1239
1226
# if we finished all children, pop it off the stack
1418
1405
inv = self.inventory
1419
1406
for entry in moved:
1421
self._move_entry(WorkingTree._RenameEntry(
1422
entry.to_rel, entry.from_id,
1408
self._move_entry(_RenameEntry(entry.to_rel, entry.from_id,
1423
1409
entry.to_tail, entry.to_parent_id, entry.from_rel,
1424
1410
entry.from_tail, entry.from_parent_id,
1425
1411
entry.only_change_inv))
1576
1562
@needs_write_lock
1577
1563
def pull(self, source, overwrite=False, stop_revision=None,
1578
1564
change_reporter=None, possible_transports=None, local=False):
1579
top_pb = ui.ui_factory.nested_progress_bar()
1565
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1580
1566
source.lock_read()
1582
1568
pp = ProgressPhase("Pull phase", 2, top_pb)
2637
2624
def _change_last_revision(self, revision_id):
2638
2625
"""See WorkingTree._change_last_revision."""
2639
if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
2626
if revision_id is None or revision_id == NULL_REVISION:
2641
2628
self._transport.delete('last-revision')
2642
2629
except errors.NoSuchFile:
2951
2938
# only set an explicit root id if there is one to set.
2952
2939
if basis_tree.inventory.root is not None:
2953
2940
wt.set_root_id(basis_tree.get_root_id())
2954
if revision_id == _mod_revision.NULL_REVISION:
2941
if revision_id == NULL_REVISION:
2955
2942
wt.set_parent_trees([])
2957
2944
wt.set_parent_trees([(revision_id, basis_tree)])