71
from bzrlib.osutils import (get_user_encoding,
72
kind_marker, isdir,isfile, is_inside_any,
71
from bzrlib.osutils import (kind_marker, isdir,isfile, is_inside_any,
73
72
is_inside_or_parent_of_any,
74
73
minimum_path_selection,
75
74
quotefn, sha_file, split_lines,
78
77
from bzrlib.testament import Testament
79
78
from bzrlib.trace import mutter, note, warning, is_quiet
79
from bzrlib.xml5 import serializer_v5
80
80
from bzrlib.inventory import InventoryEntry, make_entry
81
81
from bzrlib import symbol_versioning
82
82
from bzrlib.symbol_versioning import (deprecated_passed,
233
232
:param verbose: if True and the reporter is not None, report everything
234
233
:param recursive: If set to 'down', commit in any subtrees that have
235
234
pending changes of any sort during this commit.
236
:param exclude: None or a list of relative paths to exclude from the
237
commit. Pending changes to excluded files will be ignored by the
240
236
mutter('preparing to commit')
250
246
if message_callback is None:
251
247
if message is not None:
252
248
if isinstance(message, str):
253
message = message.decode(get_user_encoding())
249
message = message.decode(bzrlib.user_encoding)
254
250
message_callback = lambda x: message
256
252
raise BzrError("The message or message_callback keyword"
338
329
self.pb.show_count = True
339
330
self.pb.show_bar = True
332
# After a merge, a selected file commit is not supported.
333
# See 'bzr help merge' for an explanation as to why.
341
334
self.basis_inv = self.basis_tree.inventory
342
335
self._gather_parents()
343
# After a merge, a selected file commit is not supported.
344
# See 'bzr help merge' for an explanation as to why.
345
336
if len(self.parents) > 1 and self.specific_files:
346
337
raise errors.CannotCommitSelectedFileMerge(self.specific_files)
347
# Excludes are a form of selected file commit.
348
if len(self.parents) > 1 and self.exclude:
349
raise errors.CannotCommitSelectedFileMerge(self.exclude)
351
339
# Collect the changes
352
340
self._set_progress_stage("Collecting changes",
660
648
# in bugs like #46635. Any reason not to use/enhance Tree.changes_from?
661
649
# ADHB 11-07-2006
663
exclude = self.exclude
664
specific_files = self.specific_files or []
651
specific_files = self.specific_files
665
652
mutter("Selecting files for commit with filter %s", specific_files)
667
654
# Build the new inventory
668
self._populate_from_inventory()
655
self._populate_from_inventory(specific_files)
670
657
# If specific files are selected, then all un-selected files must be
671
658
# recorded in their previous state. For more details, see
672
659
# https://lists.ubuntu.com/archives/bazaar/2007q3/028476.html.
673
if specific_files or exclude:
674
661
for path, old_ie in self.basis_inv.iter_entries():
675
662
if old_ie.file_id in self.builder.new_inventory:
676
663
# already added - skip.
678
if (is_inside_any(specific_files, path)
679
and not is_inside_any(exclude, path)):
680
# was inside the selected path, and not excluded - if not
681
# present it has been deleted so skip.
665
if is_inside_any(specific_files, path):
666
# was inside the selected path, if not present it has been
683
# From here down it was either not selected, or was excluded:
684
669
if old_ie.kind == 'directory':
685
670
self._next_progress_entry()
686
# We preserve the entry unaltered.
671
# not in final inv yet, was not in the selected files, so is an
672
# entry to be preserved unaltered.
687
673
ie = old_ie.copy()
688
674
# Note: specific file commits after a merge are currently
689
675
# prohibited. This test is for sanity/safety in case it's
690
676
# required after that changes.
691
677
if len(self.parents) > 1:
692
678
ie.revision = None
693
delta, version_recorded, _ = self.builder.record_entry_contents(
679
delta, version_recorded = self.builder.record_entry_contents(
694
680
ie, self.parent_invs, path, self.basis_tree, None)
695
681
if version_recorded:
696
682
self.any_entries_changed = True
698
self._basis_delta.append(delta)
683
if delta: self._basis_delta.append(delta)
700
685
def _report_and_accumulate_deletes(self):
701
686
# XXX: Could the list of deleted paths and ids be instead taken from
712
697
self._basis_delta.append((path, None, file_id, None))
713
698
self.reporter.deleted(path)
715
def _populate_from_inventory(self):
700
def _populate_from_inventory(self, specific_files):
716
701
"""Populate the CommitBuilder by walking the working tree inventory."""
718
703
# raise an exception as soon as we find a single unknown.
719
704
for unknown in self.work_tree.unknowns():
720
705
raise StrictCommitFailed()
722
specific_files = self.specific_files
723
exclude = self.exclude
724
707
report_changes = self.reporter.is_verbose()
726
709
# A tree of paths that have been deleted. E.g. if foo/bar has been
729
712
# XXX: Note that entries may have the wrong kind because the entry does
730
713
# not reflect the status on disk.
731
714
work_inv = self.work_tree.inventory
732
# NB: entries will include entries within the excluded ids/paths
733
# because iter_entries_by_dir has no 'exclude' facility today.
734
715
entries = work_inv.iter_entries_by_dir(
735
716
specific_file_ids=self.specific_file_ids, yield_parents=True)
736
717
for path, existing_ie in entries:
758
739
if deleted_dict is not None:
759
740
# the path has a deleted parent, do not add it.
761
if exclude and is_inside_any(exclude, path):
762
# Skip excluded paths. Excluded paths are processed by
763
# _update_builder_with_changes.
765
742
content_summary = self.work_tree.path_content_summary(path)
766
743
# Note that when a filter of specific files is given, we must only
767
744
# skip/record deleted files matching that filter.
845
822
ie = existing_ie.copy()
846
823
ie.revision = None
847
# For carried over entries we don't care about the fs hash - the repo
848
# isn't generating a sha, so we're not saving computation time.
849
delta, version_recorded, fs_hash = self.builder.record_entry_contents(
850
ie, self.parent_invs, path, self.work_tree, content_summary)
824
delta, version_recorded = self.builder.record_entry_contents(ie,
825
self.parent_invs, path, self.work_tree, content_summary)
852
827
self._basis_delta.append(delta)
853
828
if version_recorded:
854
829
self.any_entries_changed = True
855
830
if report_changes:
856
831
self._report_change(ie, path)
858
self.work_tree._observed_sha1(ie.file_id, path, fs_hash)
861
834
def _report_change(self, ie, path):