90
84
from bzrlib import symbol_versioning
91
85
from bzrlib.decorators import needs_read_lock, needs_write_lock
92
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, TreeReference
93
86
from bzrlib.lockable_files import LockableFiles
94
87
from bzrlib.lockdir import LockDir
95
88
import bzrlib.mutabletree
96
89
from bzrlib.mutabletree import needs_tree_write_lock
97
90
from bzrlib import osutils
98
91
from bzrlib.osutils import (
111
102
from bzrlib.trace import mutter, note
112
103
from bzrlib.transport.local import LocalTransport
113
104
from bzrlib.progress import DummyProgress, ProgressPhase
114
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
105
from bzrlib.revision import CURRENT_REVISION
115
106
from bzrlib.rio import RioReader, rio_file, Stanza
116
from bzrlib.symbol_versioning import (deprecated_passed,
119
DEPRECATED_PARAMETER,
107
from bzrlib.symbol_versioning import (
109
DEPRECATED_PARAMETER,
123
113
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
290
280
self._control_files.break_lock()
291
281
self.branch.break_lock()
283
def _get_check_refs(self):
284
"""Return the references needed to perform a check of this tree.
286
The default implementation returns no refs, and is only suitable for
287
trees that have no local caching and can commit on ghosts at any time.
289
:seealso: bzrlib.check for details about check_refs.
293
293
def requires_rich_root(self):
294
294
return self._format.requires_rich_root
447
447
def get_file_with_stat(self, file_id, path=None, filtered=True,
448
448
_fstat=os.fstat):
449
"""See MutableTree.get_file_with_stat."""
449
"""See Tree.get_file_with_stat."""
451
451
path = self.id2path(file_id)
452
452
file_obj = self.get_file_byname(path, filtered=False)
453
453
stat_value = _fstat(file_obj.fileno())
454
if self.supports_content_filtering() and filtered:
454
if filtered and self.supports_content_filtering():
455
455
filters = self._content_filter_stack(path)
456
456
file_obj = filtered_input_file(file_obj, filters)
457
457
return (file_obj, stat_value)
462
462
def get_file_byname(self, filename, filtered=True):
463
463
path = self.abspath(filename)
464
464
f = file(path, 'rb')
465
if self.supports_content_filtering() and filtered:
465
if filtered and self.supports_content_filtering():
466
466
filters = self._content_filter_stack(filename)
467
467
return filtered_input_file(f, filters)
487
487
incorrectly attributed to CURRENT_REVISION (but after committing, the
488
488
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(),
490
maybe_file_parent_keys = []
491
for parent_id in self.get_parent_ids():
493
parent_tree = self.revision_tree(parent_id)
494
except errors.NoSuchRevisionInTree:
495
parent_tree = self.branch.repository.revision_tree(parent_id)
496
parent_tree.lock_read()
498
if file_id not in parent_tree:
500
ie = parent_tree.inventory[file_id]
501
if ie.kind != 'file':
502
# Note: this is slightly unnecessary, because symlinks and
503
# directories have a "text" which is the empty text, and we
504
# know that won't mess up annotations. But it seems cleaner
506
parent_text_key = (file_id, ie.revision)
507
if parent_text_key not in maybe_file_parent_keys:
508
maybe_file_parent_keys.append(parent_text_key)
511
graph = _mod_graph.Graph(self.branch.repository.texts)
512
heads = graph.heads(maybe_file_parent_keys)
513
file_parent_keys = []
514
for key in maybe_file_parent_keys:
516
file_parent_keys.append(key)
518
# Now we have the parents of this content
519
annotator = self.branch.repository.texts.get_annotator()
520
text = self.get_file(file_id).read()
521
this_key =(file_id, default_revision)
522
annotator.add_special_text(this_key, file_parent_keys, text)
523
annotations = [(key[-1], line)
524
for key, line in annotator.annotate_flat(this_key)]
516
527
def _get_ancestors(self, default_revision):
517
528
ancestors = set([default_revision])
533
544
parents = [last_rev]
535
merges_file = self._transport.get('pending-merges')
546
merges_bytes = self._transport.get_bytes('pending-merges')
536
547
except errors.NoSuchFile:
539
for l in merges_file.readlines():
550
for l in osutils.split_lines(merges_bytes):
540
551
revision_id = l.rstrip('\n')
541
552
parents.append(revision_id)
623
636
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
624
637
file_id = self.path2id(path)
639
# For unversioned files on win32, we just assume they are not
625
642
return self._inventory[file_id].executable
627
644
def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
738
755
kind = _mapper(stat_result.st_mode)
739
756
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(
757
return self._file_content_summary(path, stat_result)
745
758
elif kind == 'directory':
746
759
# perhaps it looks like a plain directory, but it's really a
749
762
kind = 'tree-reference'
750
763
return kind, None, None, None
751
764
elif kind == 'symlink':
752
return ('symlink', None, None,
753
os.readlink(abspath.encode(osutils._fs_enc)
754
).decode(osutils._fs_enc))
765
target = osutils.readlink(abspath)
766
return ('symlink', None, None, target)
756
768
return (kind, None, None, None)
770
def _file_content_summary(self, path, stat_result):
771
size = stat_result.st_size
772
executable = self._is_executable_from_path_and_stat(path, stat_result)
773
# try for a stat cache lookup
774
return ('file', size, executable, self._sha_from_stat(
758
777
def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
759
778
"""Common ghost checking functionality from set_parent_*.
881
900
@needs_write_lock # because merge pulls data into the branch.
882
901
def merge_from_branch(self, branch, to_revision=None, from_revision=None,
902
merge_type=None, force=False):
884
903
"""Merge from a branch into this working tree.
886
905
:param branch: The branch to merge from.
890
909
branch.last_revision().
892
911
from bzrlib.merge import Merger, Merge3Merger
893
pb = bzrlib.ui.ui_factory.nested_progress_bar()
912
pb = ui.ui_factory.nested_progress_bar()
895
914
merger = Merger(self.branch, this_tree=self, pb=pb)
896
915
merger.pp = ProgressPhase("Merge phase", 5, pb)
897
916
merger.pp.next_phase()
898
# check that there are no
900
merger.check_basis(check_clean=True, require_commits=False)
917
# check that there are no local alterations
918
if not force and self.has_changes():
919
raise errors.UncommittedChanges(self)
901
920
if to_revision is None:
902
921
to_revision = _mod_revision.ensure_null(branch.last_revision())
903
922
merger.other_rev_id = to_revision
975
994
def get_symlink_target(self, file_id):
976
return os.readlink(self.id2abspath(file_id).encode(osutils._fs_enc)
977
).decode(osutils._fs_enc)
995
abspath = self.id2abspath(file_id)
996
target = osutils.readlink(abspath)
979
999
@needs_write_lock
980
1000
def subsume(self, other_tree):
1081
1101
branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1083
1103
tree_bzrdir = branch_bzrdir
1084
wt = tree_bzrdir.create_workingtree(NULL_REVISION)
1104
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
1085
1105
wt.set_parent_ids(self.get_parent_ids())
1086
1106
my_inv = self.inventory
1087
child_inv = Inventory(root_id=None)
1107
child_inv = inventory.Inventory(root_id=None)
1088
1108
new_root = my_inv[file_id]
1089
1109
my_inv.remove_recursive_id(file_id)
1090
1110
new_root.parent_id = None
1115
1135
def _kind(self, relpath):
1116
1136
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).
1138
def list_files(self, include_root=False, from_dir=None, recursive=True):
1139
"""List all files as (path, class, kind, id, entry).
1121
1141
Lists, but does not descend into unversioned directories.
1123
1142
This does not include files that have been deleted in this
1143
tree. Skips the control directory.
1126
Skips the control directory.
1145
:param include_root: if True, do not return an entry for the root
1146
:param from_dir: start from this directory or None for the root
1147
:param recursive: whether to recurse into subdirectories or not
1128
1149
# list_files is an iterator, so @needs_read_lock doesn't work properly
1129
1150
# with it. So callers should be careful to always read_lock the tree.
1131
1152
raise errors.ObjectNotLocked(self)
1133
1154
inv = self.inventory
1134
if include_root is True:
1155
if from_dir is None and include_root is True:
1135
1156
yield ('', 'V', 'directory', inv.root.file_id, inv.root)
1136
1157
# Convert these into local objects to save lookup times
1137
1158
pathjoin = osutils.pathjoin
1144
1165
fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
1146
1167
# directory file_id, relative path, absolute path, reverse sorted children
1147
children = os.listdir(self.basedir)
1168
if from_dir is not None:
1169
from_dir_id = inv.path2id(from_dir)
1170
if from_dir_id is None:
1171
# Directory not versioned
1173
from_dir_abspath = pathjoin(self.basedir, from_dir)
1175
from_dir_id = inv.root.file_id
1176
from_dir_abspath = self.basedir
1177
children = os.listdir(from_dir_abspath)
1148
1178
children.sort()
1149
1179
# jam 20060527 The kernel sized tree seems equivalent whether we
1150
1180
# use a deque and popleft to keep them sorted, or if we use a plain
1151
1181
# list and just reverse() them.
1152
1182
children = collections.deque(children)
1153
stack = [(inv.root.file_id, u'', self.basedir, children)]
1183
stack = [(from_dir_id, u'', from_dir_abspath, children)]
1155
1185
from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
1214
1244
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
1247
# But do this child first if recursing down
1249
new_children = os.listdir(fap)
1251
new_children = collections.deque(new_children)
1252
stack.append((f_ie.file_id, fp, fap, new_children))
1253
# Break out of inner loop,
1254
# so that we start outer loop with child
1226
1257
# if we finished all children, pop it off the stack
1405
1436
inv = self.inventory
1406
1437
for entry in moved:
1408
self._move_entry(_RenameEntry(entry.to_rel, entry.from_id,
1439
self._move_entry(WorkingTree._RenameEntry(
1440
entry.to_rel, entry.from_id,
1409
1441
entry.to_tail, entry.to_parent_id, entry.from_rel,
1410
1442
entry.from_tail, entry.from_parent_id,
1411
1443
entry.only_change_inv))
1462
1494
from_tail = splitpath(from_rel)[-1]
1463
1495
from_id = inv.path2id(from_rel)
1464
1496
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]
1497
# if file is missing in the inventory maybe it's in the basis_tree
1498
basis_tree = self.branch.basis_tree()
1499
from_id = basis_tree.path2id(from_rel)
1501
raise errors.BzrRenameFailedError(from_rel,to_rel,
1502
errors.NotVersionedError(path=str(from_rel)))
1503
# put entry back in the inventory so we can rename it
1504
from_entry = basis_tree.inventory[from_id].copy()
1507
from_entry = inv[from_id]
1468
1508
from_parent_id = from_entry.parent_id
1469
1509
to_dir, to_tail = os.path.split(to_rel)
1470
1510
to_dir_id = inv.path2id(to_dir)
1562
1602
@needs_write_lock
1563
1603
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()
1604
change_reporter=None, possible_transports=None, local=False):
1605
top_pb = ui.ui_factory.nested_progress_bar()
1566
1606
source.lock_read()
1568
1608
pp = ProgressPhase("Pull phase", 2, top_pb)
1570
1610
old_revision_info = self.branch.last_revision_info()
1571
1611
basis_tree = self.basis_tree()
1572
1612
count = self.branch.pull(source, overwrite, stop_revision,
1573
possible_transports=possible_transports)
1613
possible_transports=possible_transports,
1574
1615
new_revision_info = self.branch.last_revision_info()
1575
1616
if new_revision_info != old_revision_info:
1576
1617
pp.next_phase()
1577
1618
repository = self.branch.repository
1578
pb = bzrlib.ui.ui_factory.nested_progress_bar()
1619
pb = ui.ui_factory.nested_progress_bar()
1579
1620
basis_tree.lock_read()
1581
1622
new_basis_tree = self.branch.basis_tree()
1586
1627
this_tree=self,
1588
1629
change_reporter=change_reporter)
1589
if (basis_tree.inventory.root is None and
1590
new_basis_tree.inventory.root is not None):
1591
self.set_root_id(new_basis_tree.get_root_id())
1630
basis_root_id = basis_tree.get_root_id()
1631
new_root_id = new_basis_tree.get_root_id()
1632
if basis_root_id != new_root_id:
1633
self.set_root_id(new_root_id)
1594
1636
basis_tree.unlock()
1803
1845
def _reset_data(self):
1804
1846
"""Reset transient data that cannot be revalidated."""
1805
1847
self._inventory_is_modified = False
1806
result = self._deserialize(self._transport.get('inventory'))
1848
f = self._transport.get('inventory')
1850
result = self._deserialize(f)
1807
1853
self._set_inventory(result, dirty=False)
1809
1855
@needs_tree_write_lock
1860
1906
firstline = xml.split('\n', 1)[0]
1861
1907
if (not 'revision_id="' in firstline or
1862
1908
'format="7"' not in firstline):
1863
inv = self.branch.repository.deserialise_inventory(
1909
inv = self.branch.repository._serializer.read_inventory_from_string(
1865
1911
xml = self._create_basis_xml_from_inventory(new_revision, inv)
1866
1912
self._write_basis_inventory(xml)
1867
1913
except (errors.NoSuchRevision, errors.RevisionNotPresent):
1886
1932
if self._inventory_is_modified:
1887
1933
raise errors.InventoryModified(self)
1888
result = self._deserialize(self._transport.get('inventory'))
1934
f = self._transport.get('inventory')
1936
result = self._deserialize(f)
1889
1939
self._set_inventory(result, dirty=False)
1981
2033
new_status = 'I'
1983
2035
new_status = '?'
1984
textui.show_status(new_status, self.kind(fid), f,
2036
# XXX: Really should be a more abstract reporter interface
2037
kind_ch = osutils.kind_marker(self.kind(fid))
2038
to_file.write(new_status + ' ' + f + kind_ch + '\n')
1986
2039
# Unversion file
1987
2040
inv_delta.append((f, None, fid, None))
1988
2041
message = "removed %s" % (f,)
2141
2193
raise NotImplementedError(self.unlock)
2143
def update(self, change_reporter=None, possible_transports=None):
2197
def update(self, change_reporter=None, possible_transports=None,
2198
revision=None, old_tip=_marker):
2144
2199
"""Update a working tree along its branch.
2146
2201
This will update the branch if its bound too, which means we have
2164
2219
- Merge current state -> basis tree of the master w.r.t. the old tree
2166
2221
- Do a 'normal' merge of the old branch basis if it is relevant.
2223
:param revision: The target revision to update to. Must be in the
2225
:param old_tip: If branch.update() has already been run, the value it
2226
returned (old tip of the branch or None). _marker is used
2168
2229
if self.branch.get_bound_location() is not None:
2169
2230
self.lock_write()
2170
update_branch = True
2231
update_branch = (old_tip is self._marker)
2172
2233
self.lock_tree_write()
2173
2234
update_branch = False
2175
2236
if update_branch:
2176
2237
old_tip = self.branch.update(possible_transports)
2179
return self._update_tree(old_tip, change_reporter)
2239
if old_tip is self._marker:
2241
return self._update_tree(old_tip, change_reporter, revision)
2183
2245
@needs_tree_write_lock
2184
def _update_tree(self, old_tip=None, change_reporter=None):
2246
def _update_tree(self, old_tip=None, change_reporter=None, revision=None):
2185
2247
"""Update a tree to the master branch.
2187
2249
:param old_tip: if supplied, the previous tip revision the branch,
2202
2264
last_rev = self.get_parent_ids()[0]
2203
2265
except IndexError:
2204
2266
last_rev = _mod_revision.NULL_REVISION
2205
if last_rev != _mod_revision.ensure_null(self.branch.last_revision()):
2206
# merge tree state up to new branch tip.
2267
if revision is None:
2268
revision = self.branch.last_revision()
2270
if revision not in self.branch.revision_history():
2271
raise errors.NoSuchRevision(self.branch, revision)
2272
if last_rev != _mod_revision.ensure_null(revision):
2273
# merge tree state up to specified revision.
2207
2274
basis = self.basis_tree()
2208
2275
basis.lock_read()
2210
to_tree = self.branch.basis_tree()
2211
if basis.inventory.root is None:
2212
self.set_root_id(to_tree.get_root_id())
2277
to_tree = self.branch.repository.revision_tree(revision)
2278
to_root_id = to_tree.get_root_id()
2279
if (basis.inventory.root is None
2280
or basis.inventory.root.file_id != to_root_id):
2281
self.set_root_id(to_root_id)
2214
2283
result += merge.merge_inner(
2218
2287
this_tree=self,
2219
2288
change_reporter=change_reporter)
2289
self.set_last_revision(revision)
2222
2292
# TODO - dedup parents list with things merged by pull ?
2223
2293
# reuse the tree we've updated to to set the basis:
2224
parent_trees = [(self.branch.last_revision(), to_tree)]
2294
parent_trees = [(revision, to_tree)]
2225
2295
merges = self.get_parent_ids()[1:]
2226
2296
# Ideally we ask the tree for the trees here, that way the working
2227
2297
# tree can decide whether to give us the entire tree or give us a
2257
2327
# should be able to remove this extra flush.
2259
2329
graph = self.branch.repository.get_graph()
2260
base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
2330
base_rev_id = graph.find_unique_lca(revision, old_tip)
2262
2331
base_tree = self.branch.repository.revision_tree(base_rev_id)
2263
2332
other_tree = self.branch.repository.revision_tree(old_tip)
2264
2333
result += merge.merge_inner(
2373
2442
bzrdir_loc = bisect_left(cur_disk_dir_content,
2374
2443
('.bzr', '.bzr'))
2375
2444
if (bzrdir_loc < len(cur_disk_dir_content)
2376
and cur_disk_dir_content[bzrdir_loc][0] == '.bzr'):
2445
and self.bzrdir.is_control_filename(
2446
cur_disk_dir_content[bzrdir_loc][0])):
2377
2447
# we dont yield the contents of, or, .bzr itself.
2378
2448
del cur_disk_dir_content[bzrdir_loc]
2379
2449
if inv_finished:
2513
2583
return un_resolved, resolved
2515
2585
@needs_read_lock
2586
def _check(self, references):
2587
"""Check the tree for consistency.
2589
:param references: A dict with keys matching the items returned by
2590
self._get_check_refs(), and values from looking those keys up in
2517
2593
tree_basis = self.basis_tree()
2518
2594
tree_basis.lock_read()
2520
repo_basis = self.branch.repository.revision_tree(
2521
self.last_revision())
2596
repo_basis = references[('trees', self.last_revision())]
2522
2597
if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2523
2598
raise errors.BzrCheckError(
2524
2599
"Mismatched basis inventory content.")
2570
2644
if self._inventory is None:
2571
2645
self.read_working_inventory()
2647
def _get_check_refs(self):
2648
"""Return the references needed to perform a check of this tree."""
2649
return [('trees', self.last_revision())]
2573
2651
def lock_tree_write(self):
2574
2652
"""See WorkingTree.lock_tree_write().
2622
2700
def _change_last_revision(self, revision_id):
2623
2701
"""See WorkingTree._change_last_revision."""
2624
if revision_id is None or revision_id == NULL_REVISION:
2702
if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
2626
2704
self._transport.delete('last-revision')
2627
2705
except errors.NoSuchFile:
2632
2710
mode=self.bzrdir._get_file_mode())
2713
def _get_check_refs(self):
2714
"""Return the references needed to perform a check of this tree."""
2715
return [('trees', self.last_revision())]
2635
2717
@needs_tree_write_lock
2636
2718
def set_conflicts(self, conflicts):
2637
2719
self._put_rio('conflicts', conflicts.to_stanzas(),
2714
2796
"""Return the format for the working tree object in a_bzrdir."""
2716
2798
transport = a_bzrdir.get_workingtree_transport(None)
2717
format_string = transport.get("format").read()
2799
format_string = transport.get_bytes("format")
2718
2800
return klass._formats[format_string]
2719
2801
except errors.NoSuchFile:
2720
2802
raise errors.NoWorkingTree(base=transport.base)
2936
3018
# only set an explicit root id if there is one to set.
2937
3019
if basis_tree.inventory.root is not None:
2938
3020
wt.set_root_id(basis_tree.get_root_id())
2939
if revision_id == NULL_REVISION:
3021
if revision_id == _mod_revision.NULL_REVISION:
2940
3022
wt.set_parent_trees([])
2942
3024
wt.set_parent_trees([(revision_id, basis_tree)])
2984
3066
return self.get_format_string()
2987
__default_format = WorkingTreeFormat4()
3069
__default_format = WorkingTreeFormat6()
2988
3070
WorkingTreeFormat.register_format(__default_format)
2989
WorkingTreeFormat.register_format(WorkingTreeFormat6())
2990
3071
WorkingTreeFormat.register_format(WorkingTreeFormat5())
3072
WorkingTreeFormat.register_format(WorkingTreeFormat4())
2991
3073
WorkingTreeFormat.register_format(WorkingTreeFormat3())
2992
3074
WorkingTreeFormat.set_default_format(__default_format)
2993
3075
# formats which have no format string are not discoverable