71
from bzrlib.osutils import (kind_marker, isdir,isfile, is_inside_any,
71
from bzrlib.osutils import (kind_marker, isdir,isfile, is_inside_any,
72
72
is_inside_or_parent_of_any,
73
minimum_path_selection,
73
74
quotefn, sha_file, split_lines)
74
75
from bzrlib.testament import Testament
75
76
from bzrlib.trace import mutter, note, warning, is_quiet
241
242
" parameter is required for commit().")
243
244
self.bound_branch = None
245
self.any_entries_changed = False
246
self.any_entries_deleted = False
244
247
self.local = local
245
248
self.master_branch = None
246
249
self.master_locked = False
247
250
self.rev_id = None
248
self.specific_files = specific_files
251
if specific_files is not None:
252
self.specific_files = sorted(
253
minimum_path_selection(specific_files))
255
self.specific_files = None
256
self.specific_file_ids = None
249
257
self.allow_pointless = allow_pointless
250
258
self.revprops = revprops
251
259
self.message_callback = message_callback
279
287
self.config = self.branch.get_config()
281
289
# If provided, ensure the specified files are versioned
282
if specific_files is not None:
283
# Note: We don't actually need the IDs here. This routine
284
# is being called because it raises PathNotVerisonedError
285
# as a side effect of finding the IDs.
290
if self.specific_files is not None:
291
# Note: This routine is being called because it raises
292
# PathNotVerisonedError as a side effect of finding the IDs. We
293
# later use the ids we found as input to the working tree
294
# inventory iterator, so we only consider those ids rather than
295
# examining the whole tree again.
286
296
# XXX: Dont we have filter_unversioned to do this more
288
tree.find_ids_across_trees(specific_files,
289
[self.basis_tree, self.work_tree])
298
self.specific_file_ids = tree.find_ids_across_trees(
299
specific_files, [self.basis_tree, self.work_tree])
291
301
# Setup the progress bar. As the number of files that need to be
292
302
# committed in unknown, progress is reported as stages.
384
394
return NullCommitReporter()
385
395
return ReportCommitToLog()
387
def _any_real_changes(self):
388
"""Are there real changes between new_inventory and basis?
390
For trees without rich roots, inv.root.revision changes every commit.
391
But if that is the only change, we want to treat it as though there
394
new_entries = self.builder.new_inventory.iter_entries()
395
basis_entries = self.basis_inv.iter_entries()
396
new_path, new_root_ie = new_entries.next()
397
basis_path, basis_root_ie = basis_entries.next()
399
# This is a copy of InventoryEntry.__eq__ only leaving out .revision
400
def ie_equal_no_revision(this, other):
401
return ((this.file_id == other.file_id)
402
and (this.name == other.name)
403
and (this.symlink_target == other.symlink_target)
404
and (this.text_sha1 == other.text_sha1)
405
and (this.text_size == other.text_size)
406
and (this.text_id == other.text_id)
407
and (this.parent_id == other.parent_id)
408
and (this.kind == other.kind)
409
and (this.executable == other.executable)
410
and (this.reference_revision == other.reference_revision)
412
if not ie_equal_no_revision(new_root_ie, basis_root_ie):
415
for new_ie, basis_ie in zip(new_entries, basis_entries):
416
if new_ie != basis_ie:
419
# No actual changes present
422
397
def _check_pointless(self):
423
398
if self.allow_pointless:
436
411
# If length == 1, then we only have the root entry. Which means
437
412
# that there is no real difference (only the root could be different)
438
if (len(self.builder.new_inventory) != 1 and self._any_real_changes()):
413
if len(self.builder.new_inventory) != 1 and (self.any_entries_changed
414
or self.any_entries_deleted):
440
416
raise PointlessCommit()
672
648
# recorded in their previous state. For more details, see
673
649
# https://lists.ubuntu.com/archives/bazaar/2007q3/028476.html.
674
650
if specific_files:
675
for path, new_ie in self.basis_inv.iter_entries():
676
if new_ie.file_id in self.builder.new_inventory:
651
for path, old_ie in self.basis_inv.iter_entries():
652
if old_ie.file_id in self.builder.new_inventory:
677
653
# already added - skip.
679
655
if is_inside_any(specific_files, path):
680
656
# was inside the selected path, if not present it has been
681
657
# deleted so skip.
659
if old_ie.kind == 'directory':
660
self._next_progress_entry()
683
661
# not in final inv yet, was not in the selected files, so is an
684
662
# entry to be preserved unaltered.
686
self.builder.record_entry_contents(ie, self.parent_invs, path,
687
self.basis_tree, None)
664
# Note: specific file commits after a merge are currently
665
# prohibited. This test is for sanity/safety in case it's
666
# required after that changes.
667
if len(self.parents) > 1:
669
if self.builder.record_entry_contents(ie, self.parent_invs, path,
670
self.basis_tree, None):
671
self.any_entries_changed = True
673
# note that deletes have occurred
674
if set(self.basis_inv._byid.keys()) - set(self.builder.new_inventory._byid.keys()):
675
self.any_entries_deleted = True
689
676
# Report what was deleted.
690
if self.reporter.is_verbose():
677
if self.any_entries_deleted and self.reporter.is_verbose():
691
678
for path, ie in self.basis_inv.iter_entries():
692
679
if ie.file_id not in self.builder.new_inventory:
693
680
self.reporter.deleted(path)
704
691
deleted_paths = set()
705
692
work_inv = self.work_tree.inventory
706
693
assert work_inv.root is not None
707
entries = work_inv.iter_entries()
708
694
# XXX: Note that entries may have the wrong kind.
695
entries = work_inv.iter_entries_by_dir(
696
specific_file_ids=self.specific_file_ids, yield_parents=True)
709
697
if not self.builder.record_root_entry:
711
699
for path, existing_ie in entries:
794
781
content_summary):
795
782
"Record the new inventory entry for a path if any."
796
783
# mutter('check %s {%s}', path, file_id)
797
if (not specific_files or
798
is_inside_or_parent_of_any(specific_files, path)):
799
# mutter('%s selected for commit', path)
800
if definitely_changed or existing_ie is None:
801
ie = inventory.make_entry(kind, name, parent_id, file_id)
803
ie = existing_ie.copy()
784
# mutter('%s selected for commit', path)
785
if definitely_changed or existing_ie is None:
786
ie = inventory.make_entry(kind, name, parent_id, file_id)
806
# mutter('%s not selected for commit', path)
807
if self.basis_inv.has_id(file_id):
808
ie = self.basis_inv[file_id].copy()
810
# this entry is new and not being committed
813
self.builder.record_entry_contents(ie, self.parent_invs,
814
path, self.work_tree, content_summary)
816
self._report_change(ie, path)
788
ie = existing_ie.copy()
790
if self.builder.record_entry_contents(ie, self.parent_invs,
791
path, self.work_tree, content_summary):
792
self.any_entries_changed = True
794
self._report_change(ie, path)
819
797
def _report_change(self, ie, path):