91
93
want_unversioned=want_unversioned,
94
def _iter_changes(self, from_tree, include_unchanged=False,
96
@symbol_versioning.deprecated_method(symbol_versioning.one_three)
97
def _iter_changes(self, *args, **kwargs):
98
return self.iter_changes(*args, **kwargs)
100
def iter_changes(self, from_tree, include_unchanged=False,
95
101
specific_files=None, pb=None, extra_trees=None,
96
102
require_versioned=True, want_unversioned=False):
97
103
intertree = InterTree.get(from_tree, self)
98
return intertree._iter_changes(include_unchanged, specific_files, pb,
104
return intertree.iter_changes(include_unchanged, specific_files, pb,
99
105
extra_trees, require_versioned, want_unversioned=want_unversioned)
101
107
def conflicts(self):
186
193
raise NotImplementedError("Tree subclass %s must implement kind"
187
194
% self.__class__.__name__)
196
def stored_kind(self, file_id):
197
"""File kind stored for this file_id.
199
May not match kind on disk for working trees. Always available
200
for versioned files, even when the file itself is missing.
202
return self.kind(file_id)
204
def path_content_summary(self, path):
205
"""Get a summary of the information about path.
207
:param path: A relative path within the tree.
208
:return: A tuple containing kind, size, exec, sha1-or-link.
209
Kind is always present (see tree.kind()).
210
size is present if kind is file, None otherwise.
211
exec is None unless kind is file and the platform supports the 'x'
213
sha1-or-link is the link target if kind is symlink, or the sha1 if
214
it can be obtained without reading the file.
216
raise NotImplementedError(self.path_content_summary)
189
218
def get_reference_revision(self, file_id, path=None):
190
219
raise NotImplementedError("Tree subclass %s must implement "
191
220
"get_reference_revision"
222
255
raise NotImplementedError(self.get_file_mtime)
224
257
def get_file_by_path(self, path):
225
return self.get_file(self._inventory.path2id(path))
258
return self.get_file(self._inventory.path2id(path), path)
260
def iter_files_bytes(self, desired_files):
261
"""Iterate through file contents.
263
Files will not necessarily be returned in the order they occur in
264
desired_files. No specific order is guaranteed.
266
Yields pairs of identifier, bytes_iterator. identifier is an opaque
267
value supplied by the caller as part of desired_files. It should
268
uniquely identify the file version in the caller's context. (Examples:
269
an index number or a TreeTransform trans_id.)
271
bytes_iterator is an iterable of bytestrings for the file. The
272
kind of iterable and length of the bytestrings are unspecified, but for
273
this implementation, it is a tuple containing a single bytestring with
274
the complete text of the file.
276
:param desired_files: a list of (file_id, identifier) pairs
278
for file_id, identifier in desired_files:
279
# We wrap the string in a tuple so that we can return an iterable
280
# of bytestrings. (Technically, a bytestring is also an iterable
281
# of bytestrings, but iterating through each character is not
283
cur_file = (self.get_file_text(file_id),)
284
yield identifier, cur_file
227
286
def get_symlink_target(self, file_id):
228
287
"""Get the target for a given file_id.
235
294
raise NotImplementedError(self.get_symlink_target)
237
def annotate_iter(self, file_id):
238
"""Return an iterator of revision_id, line tuples
296
def get_root_id(self):
297
"""Return the file_id for the root of this tree."""
298
raise NotImplementedError(self.get_root_id)
300
def annotate_iter(self, file_id,
301
default_revision=_mod_revision.CURRENT_REVISION):
302
"""Return an iterator of revision_id, line tuples.
240
304
For working trees (and mutable trees in general), the special
241
305
revision_id 'current:' will be used for lines that are new in this
242
306
tree, e.g. uncommitted changes.
243
307
:param file_id: The file to produce an annotated version from
308
:param default_revision: For lines that don't match a basis, mark them
309
with this revision id. Not all implementations will make use of
245
312
raise NotImplementedError(self.annotate_iter)
314
def _get_plan_merge_data(self, file_id, other, base):
315
from bzrlib import merge, versionedfile
316
vf = versionedfile._PlanMergeVersionedFile(file_id)
317
last_revision_a = self._get_file_revision(file_id, vf, 'this:')
318
last_revision_b = other._get_file_revision(file_id, vf, 'other:')
320
last_revision_base = None
322
last_revision_base = base._get_file_revision(file_id, vf, 'base:')
323
return vf, last_revision_a, last_revision_b, last_revision_base
325
def plan_file_merge(self, file_id, other, base=None):
326
"""Generate a merge plan based on annotations.
328
If the file contains uncommitted changes in this tree, they will be
329
attributed to the 'current:' pseudo-revision. If the file contains
330
uncommitted changes in the other tree, they will be assigned to the
331
'other:' pseudo-revision.
333
data = self._get_plan_merge_data(file_id, other, base)
334
vf, last_revision_a, last_revision_b, last_revision_base = data
335
return vf.plan_merge(last_revision_a, last_revision_b,
338
def plan_file_lca_merge(self, file_id, other, base=None):
339
"""Generate a merge plan based lca-newness.
341
If the file contains uncommitted changes in this tree, they will be
342
attributed to the 'current:' pseudo-revision. If the file contains
343
uncommitted changes in the other tree, they will be assigned to the
344
'other:' pseudo-revision.
346
data = self._get_plan_merge_data(file_id, other, base)
347
vf, last_revision_a, last_revision_b, last_revision_base = data
348
return vf.plan_lca_merge(last_revision_a, last_revision_b,
351
def _get_file_revision(self, file_id, vf, tree_revision):
352
def file_revision(revision_tree):
353
revision_tree.lock_read()
355
return revision_tree.inventory[file_id].revision
357
revision_tree.unlock()
359
def iter_parent_trees():
360
for revision_id in self.get_parent_ids():
362
yield self.revision_tree(revision_id)
364
yield self.repository.revision_tree(revision_id)
366
if getattr(self, '_get_weave', None) is None:
367
last_revision = tree_revision
368
parent_revisions = [file_revision(t) for t in iter_parent_trees()]
369
vf.add_lines(last_revision, parent_revisions,
370
self.get_file(file_id).readlines())
371
repo = self.branch.repository
372
transaction = repo.get_transaction()
373
base_vf = repo.weave_store.get_weave(file_id, transaction)
375
last_revision = file_revision(self)
376
base_vf = self._get_weave(file_id)
377
vf.fallback_versionedfiles.append(base_vf)
247
380
inventory = property(_get_inventory,
248
381
doc="Inventory of this Tree")
594
724
return delta._compare_trees(self.source, self.target, want_unchanged,
595
725
specific_files, include_root, extra_trees=extra_trees,
726
require_versioned=require_versioned,
596
727
want_unversioned=want_unversioned)
598
def _iter_changes(self, include_unchanged=False,
729
def iter_changes(self, include_unchanged=False,
599
730
specific_files=None, pb=None, extra_trees=[],
600
731
require_versioned=True, want_unversioned=False):
601
732
"""Generate an iterator of changes between trees.
629
760
lookup_trees = [self.source]
631
762
lookup_trees.extend(extra_trees)
632
specific_file_ids = self.target.paths2ids(specific_files,
633
lookup_trees, require_versioned=require_versioned)
763
if specific_files == []:
764
specific_file_ids = []
766
specific_file_ids = self.target.paths2ids(specific_files,
767
lookup_trees, require_versioned=require_versioned)
634
768
if want_unversioned:
635
all_unversioned = sorted([(p.split('/'), p) for p in self.target.extras()
636
if not specific_files or
769
all_unversioned = sorted([(p.split('/'), p) for p in
771
if specific_files is None or
637
772
osutils.is_inside_any(specific_files, p)])
638
773
all_unversioned = deque(all_unversioned)