61
58
trees or versioned trees.
64
def has_versioned_directories(self):
65
"""Whether this tree can contain explicitly versioned directories.
67
This defaults to True, but some implementations may want to override
72
61
def changes_from(self, other, want_unchanged=False, specific_files=None,
73
62
extra_trees=None, require_versioned=False, include_root=False,
74
63
want_unversioned=False):
138
127
def has_id(self, file_id):
139
128
raise NotImplementedError(self.has_id)
141
@deprecated_method(deprecated_in((2, 4, 0)))
142
130
def __contains__(self, file_id):
143
131
return self.has_id(file_id)
306
290
:param file_id: The file_id of the file.
307
291
:param path: The path of the file.
309
292
If both file_id and path are supplied, an implementation may use
312
295
return osutils.split_lines(self.get_file_text(file_id, path))
314
def get_file_verifier(self, file_id, path=None, stat_value=None):
315
"""Return a verifier for a file.
317
The default implementation returns a sha1.
319
:param file_id: The handle for this file.
320
:param path: The path that this file can be found at.
321
These must point to the same object.
322
:param stat_value: Optional stat value for the object
323
:return: Tuple with verifier name and verifier data
325
return ("SHA1", self.get_file_sha1(file_id, path=path,
326
stat_value=stat_value))
328
def get_file_sha1(self, file_id, path=None, stat_value=None):
297
def get_file_sha1(self, file_id, path=None):
329
298
"""Return the SHA1 file for a file.
331
:note: callers should use get_file_verifier instead
332
where possible, as the underlying repository implementation may
333
have quicker access to a non-sha1 verifier.
335
300
:param file_id: The handle for this file.
336
301
:param path: The path that this file can be found at.
337
302
These must point to the same object.
338
:param stat_value: Optional stat value for the object
340
304
raise NotImplementedError(self.get_file_sha1)
358
322
raise NotImplementedError(self.get_file_size)
324
def get_file_by_path(self, path):
325
raise NotImplementedError(self.get_file_by_path)
360
327
def is_executable(self, file_id, path=None):
361
328
"""Check if a file is executable.
392
359
cur_file = (self.get_file_text(file_id),)
393
360
yield identifier, cur_file
395
def get_symlink_target(self, file_id, path=None):
362
def get_symlink_target(self, file_id):
396
363
"""Get the target for a given file_id.
398
365
It is assumed that the caller already knows that file_id is referencing
400
367
:param file_id: Handle for the symlink entry.
401
:param path: The path of the file.
402
If both file_id and path are supplied, an implementation may use
404
368
:return: The path the symlink points to.
406
370
raise NotImplementedError(self.get_symlink_target)
408
373
def get_root_id(self):
409
374
"""Return the file_id for the root of this tree."""
410
375
raise NotImplementedError(self.get_root_id)
631
596
prefs = self.iter_search_rules([path], filter_pref_names).next()
632
597
stk = filters._get_filter_stack_for(prefs)
633
598
if 'filters' in debug.debug_flags:
634
trace.note(gettext("*** {0} content-filter: {1} => {2!r}").format(path,prefs,stk))
599
trace.note("*** %s content-filter: %s => %r" % (path,prefs,stk))
637
602
def _content_filter_stack_provider(self):
826
791
return self.inventory.iter_entries_by_dir(
827
792
specific_file_ids=specific_file_ids, yield_parents=yield_parents)
829
@deprecated_method(deprecated_in((2, 5, 0)))
830
794
def get_file_by_path(self, path):
831
return self.get_file(self.path2id(path), path)
795
return self.get_file(self._inventory.path2id(path), path)
798
######################################################################
801
# TODO: Merge these two functions into a single one that can operate
802
# on either a whole tree or a set of files.
804
# TODO: Return the diff in order by filename, not by category or in
805
# random order. Can probably be done by lock-stepping through the
806
# filenames from both trees.
809
def file_status(filename, old_tree, new_tree):
810
"""Return single-letter status, old and new names for a file.
812
The complexity here is in deciding how to represent renames;
813
many complex cases are possible.
815
old_inv = old_tree.inventory
816
new_inv = new_tree.inventory
817
new_id = new_inv.path2id(filename)
818
old_id = old_inv.path2id(filename)
820
if not new_id and not old_id:
821
# easy: doesn't exist in either; not versioned at all
822
if new_tree.is_ignored(filename):
823
return 'I', None, None
825
return '?', None, None
827
# There is now a file of this name, great.
830
# There is no longer a file of this name, but we can describe
831
# what happened to the file that used to have
832
# this name. There are two possibilities: either it was
833
# deleted entirely, or renamed.
834
if new_inv.has_id(old_id):
835
return 'X', old_inv.id2path(old_id), new_inv.id2path(old_id)
837
return 'D', old_inv.id2path(old_id), None
839
# if the file_id is new in this revision, it is added
840
if new_id and not old_inv.has_id(new_id):
843
# if there used to be a file of this name, but that ID has now
844
# disappeared, it is deleted
845
if old_id and not new_inv.has_id(old_id):
834
851
def find_ids_across_trees(filenames, trees, require_versioned=True):
982
999
if source_kind != target_kind:
983
1000
changed_content = True
984
1001
elif source_kind == 'file':
985
if not self.file_content_matches(file_id, file_id, source_path,
986
target_path, source_stat, target_stat):
1002
if (self.source.get_file_sha1(file_id, source_path, source_stat) !=
1003
self.target.get_file_sha1(file_id, target_path, target_stat)):
987
1004
changed_content = True
988
1005
elif source_kind == 'symlink':
989
1006
if (self.source.get_symlink_target(file_id) !=
1302
1319
changed_file_ids.add(result[0])
1306
def file_content_matches(self, source_file_id, target_file_id,
1307
source_path=None, target_path=None, source_stat=None, target_stat=None):
1308
"""Check if two files are the same in the source and target trees.
1310
This only checks that the contents of the files are the same,
1311
it does not touch anything else.
1313
:param source_file_id: File id of the file in the source tree
1314
:param target_file_id: File id of the file in the target tree
1315
:param source_path: Path of the file in the source tree
1316
:param target_path: Path of the file in the target tree
1317
:param source_stat: Optional stat value of the file in the source tree
1318
:param target_stat: Optional stat value of the file in the target tree
1319
:return: Boolean indicating whether the files have the same contents
1321
source_verifier_kind, source_verifier_data = self.source.get_file_verifier(
1322
source_file_id, source_path, source_stat)
1323
target_verifier_kind, target_verifier_data = self.target.get_file_verifier(
1324
target_file_id, target_path, target_stat)
1325
if source_verifier_kind == target_verifier_kind:
1326
return (source_verifier_data == target_verifier_data)
1327
# Fall back to SHA1 for now
1328
if source_verifier_kind != "SHA1":
1329
source_sha1 = self.source.get_file_sha1(source_file_id,
1330
source_path, source_stat)
1332
source_sha1 = source_verifier_data
1333
if target_verifier_kind != "SHA1":
1334
target_sha1 = self.target.get_file_sha1(target_file_id,
1335
target_path, target_stat)
1337
target_sha1 = target_verifier_data
1338
return (source_sha1 == target_sha1)
1340
1323
InterTree.register_optimiser(InterTree)