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"
448
457
def get_file_with_stat(self, file_id, path=None, filtered=True,
449
458
_fstat=os.fstat):
450
"""See Tree.get_file_with_stat."""
459
"""See MutableTree.get_file_with_stat."""
452
461
path = self.id2path(file_id)
453
462
file_obj = self.get_file_byname(path, filtered=False)
454
463
stat_value = _fstat(file_obj.fileno())
455
if filtered and self.supports_content_filtering():
464
if self.supports_content_filtering() and filtered:
456
465
filters = self._content_filter_stack(path)
457
466
file_obj = filtered_input_file(file_obj, filters)
458
467
return (file_obj, stat_value)
463
472
def get_file_byname(self, filename, filtered=True):
464
473
path = self.abspath(filename)
465
474
f = file(path, 'rb')
466
if filtered and self.supports_content_filtering():
475
if self.supports_content_filtering() and filtered:
467
476
filters = self._content_filter_stack(filename)
468
477
return filtered_input_file(f, filters)
488
497
incorrectly attributed to CURRENT_REVISION (but after committing, the
489
498
attribution will be correct).
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)]
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(),
528
526
def _get_ancestors(self, default_revision):
529
527
ancestors = set([default_revision])
752
748
kind = _mapper(stat_result.st_mode)
753
749
if kind == 'file':
754
return self._file_content_summary(path, stat_result)
750
size = stat_result.st_size
751
# try for a stat cache lookup
752
executable = self._is_executable_from_path_and_stat(path, stat_result)
753
return (kind, size, executable, self._sha_from_stat(
755
755
elif kind == 'directory':
756
756
# perhaps it looks like a plain directory, but it's really a
765
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(
774
767
def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
775
768
"""Common ghost checking functionality from set_parent_*.
906
899
branch.last_revision().
908
901
from bzrlib.merge import Merger, Merge3Merger
909
pb = ui.ui_factory.nested_progress_bar()
902
pb = bzrlib.ui.ui_factory.nested_progress_bar()
911
904
merger = Merger(self.branch, this_tree=self, pb=pb)
912
905
merger.pp = ProgressPhase("Merge phase", 5, pb)
1098
1091
branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1100
1093
tree_bzrdir = branch_bzrdir
1101
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
1094
wt = tree_bzrdir.create_workingtree(NULL_REVISION)
1102
1095
wt.set_parent_ids(self.get_parent_ids())
1103
1096
my_inv = self.inventory
1104
child_inv = inventory.Inventory(root_id=None)
1097
child_inv = Inventory(root_id=None)
1105
1098
new_root = my_inv[file_id]
1106
1099
my_inv.remove_recursive_id(file_id)
1107
1100
new_root.parent_id = None
1132
1125
def _kind(self, relpath):
1133
1126
return osutils.file_kind(self.abspath(relpath))
1135
def list_files(self, include_root=False, from_dir=None, recursive=True):
1136
"""List all files as (path, class, kind, id, entry).
1128
def list_files(self, include_root=False):
1129
"""Recursively list all files as (path, class, kind, id, entry).
1138
1131
Lists, but does not descend into unversioned directories.
1139
1133
This does not include files that have been deleted in this
1140
tree. 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
1136
Skips the control directory.
1146
1138
# list_files is an iterator, so @needs_read_lock doesn't work properly
1147
1139
# with it. So callers should be careful to always read_lock the tree.
1149
1141
raise errors.ObjectNotLocked(self)
1151
1143
inv = self.inventory
1152
if from_dir is None and include_root is True:
1144
if include_root is True:
1153
1145
yield ('', 'V', 'directory', inv.root.file_id, inv.root)
1154
1146
# Convert these into local objects to save lookup times
1155
1147
pathjoin = osutils.pathjoin
1162
1154
fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
1164
1156
# directory file_id, relative path, absolute path, reverse sorted children
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)
1157
children = os.listdir(self.basedir)
1175
1158
children.sort()
1176
1159
# jam 20060527 The kernel sized tree seems equivalent whether we
1177
1160
# use a deque and popleft to keep them sorted, or if we use a plain
1178
1161
# list and just reverse() them.
1179
1162
children = collections.deque(children)
1180
stack = [(from_dir_id, u'', from_dir_abspath, children)]
1163
stack = [(inv.root.file_id, u'', self.basedir, children)]
1182
1165
from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
1241
1224
if fk != 'directory':
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
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
1254
1236
# if we finished all children, pop it off the stack
1433
1415
inv = self.inventory
1434
1416
for entry in moved:
1436
self._move_entry(WorkingTree._RenameEntry(
1437
entry.to_rel, entry.from_id,
1418
self._move_entry(_RenameEntry(entry.to_rel, entry.from_id,
1438
1419
entry.to_tail, entry.to_parent_id, entry.from_rel,
1439
1420
entry.from_tail, entry.from_parent_id,
1440
1421
entry.only_change_inv))
1491
1472
from_tail = splitpath(from_rel)[-1]
1492
1473
from_id = inv.path2id(from_rel)
1493
1474
if from_id is None:
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]
1475
raise errors.BzrRenameFailedError(from_rel,to_rel,
1476
errors.NotVersionedError(path=str(from_rel)))
1477
from_entry = inv[from_id]
1505
1478
from_parent_id = from_entry.parent_id
1506
1479
to_dir, to_tail = os.path.split(to_rel)
1507
1480
to_dir_id = inv.path2id(to_dir)
1599
1572
@needs_write_lock
1600
1573
def pull(self, source, overwrite=False, stop_revision=None,
1601
change_reporter=None, possible_transports=None, local=False):
1602
top_pb = ui.ui_factory.nested_progress_bar()
1574
change_reporter=None, possible_transports=None):
1575
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1603
1576
source.lock_read()
1605
1578
pp = ProgressPhase("Pull phase", 2, top_pb)
1607
1580
old_revision_info = self.branch.last_revision_info()
1608
1581
basis_tree = self.basis_tree()
1609
1582
count = self.branch.pull(source, overwrite, stop_revision,
1610
possible_transports=possible_transports,
1583
possible_transports=possible_transports)
1612
1584
new_revision_info = self.branch.last_revision_info()
1613
1585
if new_revision_info != old_revision_info:
1614
1586
pp.next_phase()
1615
1587
repository = self.branch.repository
1616
pb = ui.ui_factory.nested_progress_bar()
1588
pb = bzrlib.ui.ui_factory.nested_progress_bar()
1617
1589
basis_tree.lock_read()
1619
1591
new_basis_tree = self.branch.basis_tree()
1898
1870
firstline = xml.split('\n', 1)[0]
1899
1871
if (not 'revision_id="' in firstline or
1900
1872
'format="7"' not in firstline):
1901
inv = self.branch.repository._serializer.read_inventory_from_string(
1873
inv = self.branch.repository.deserialise_inventory(
1903
1875
xml = self._create_basis_xml_from_inventory(new_revision, inv)
1904
1876
self._write_basis_inventory(xml)
1905
1877
except (errors.NoSuchRevision, errors.RevisionNotPresent):
2410
2383
bzrdir_loc = bisect_left(cur_disk_dir_content,
2411
2384
('.bzr', '.bzr'))
2412
2385
if (bzrdir_loc < len(cur_disk_dir_content)
2413
and self.bzrdir.is_control_filename(
2414
cur_disk_dir_content[bzrdir_loc][0])):
2386
and cur_disk_dir_content[bzrdir_loc][0] == '.bzr'):
2415
2387
# we dont yield the contents of, or, .bzr itself.
2416
2388
del cur_disk_dir_content[bzrdir_loc]
2417
2389
if inv_finished:
2669
2641
def _change_last_revision(self, revision_id):
2670
2642
"""See WorkingTree._change_last_revision."""
2671
if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
2643
if revision_id is None or revision_id == NULL_REVISION:
2673
2645
self._transport.delete('last-revision')
2674
2646
except errors.NoSuchFile:
2987
2959
# only set an explicit root id if there is one to set.
2988
2960
if basis_tree.inventory.root is not None:
2989
2961
wt.set_root_id(basis_tree.get_root_id())
2990
if revision_id == _mod_revision.NULL_REVISION:
2962
if revision_id == NULL_REVISION:
2991
2963
wt.set_parent_trees([])
2993
2965
wt.set_parent_trees([(revision_id, basis_tree)])
3035
3007
return self.get_format_string()
3038
__default_format = WorkingTreeFormat6()
3010
__default_format = WorkingTreeFormat4()
3039
3011
WorkingTreeFormat.register_format(__default_format)
3012
WorkingTreeFormat.register_format(WorkingTreeFormat6())
3040
3013
WorkingTreeFormat.register_format(WorkingTreeFormat5())
3041
WorkingTreeFormat.register_format(WorkingTreeFormat4())
3042
3014
WorkingTreeFormat.register_format(WorkingTreeFormat3())
3043
3015
WorkingTreeFormat.set_default_format(__default_format)
3044
3016
# formats which have no format string are not discoverable