~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commit.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-06-08 00:21:20 UTC
  • mfrom: (3453.2.11 fast-checkout2)
  • Revision ID: pqm@pqm.ubuntu.com-20080608002120-r3kcq0kxq24lhnak
Improve build_tree performance (igc, abentley)

Show diffs side-by-side

added added

removed removed

Lines of Context:
68
68
                           ConflictsInTree,
69
69
                           StrictCommitFailed
70
70
                           )
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,
77
76
                            )
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,
204
204
               reporter=None,
205
205
               config=None,
206
206
               message_callback=None,
207
 
               recursive='down',
208
 
               exclude=None):
 
207
               recursive='down'):
209
208
        """Commit working copy as a new revision.
210
209
 
211
210
        :param message: the commit message (it or message_callback is required)
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
238
 
            commit. 
239
235
        """
240
236
        mutter('preparing to commit')
241
237
 
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
255
251
            else:
256
252
                raise BzrError("The message or message_callback keyword"
259
255
        self.bound_branch = None
260
256
        self.any_entries_changed = False
261
257
        self.any_entries_deleted = False
262
 
        if exclude is not None:
263
 
            self.exclude = sorted(
264
 
                minimum_path_selection(exclude))
265
 
        else:
266
 
            self.exclude = []
267
258
        self.local = local
268
259
        self.master_branch = None
269
260
        self.master_locked = False
338
329
            self.pb.show_count = True
339
330
            self.pb.show_bar = True
340
331
 
 
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)
350
338
 
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
662
650
 
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)
666
653
 
667
654
        # Build the new inventory
668
 
        self._populate_from_inventory()
 
655
        self._populate_from_inventory(specific_files)
669
656
 
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:
 
660
        if specific_files:
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.
677
664
                    continue
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
 
667
                    # deleted so skip.
682
668
                    continue
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
697
 
                if delta:
698
 
                    self._basis_delta.append(delta)
 
683
                if delta: self._basis_delta.append(delta)
699
684
 
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)
714
699
 
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."""
717
702
        if self.strict:
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()
721
 
        
722
 
        specific_files = self.specific_files
723
 
        exclude = self.exclude
 
706
               
724
707
        report_changes = self.reporter.is_verbose()
725
708
        deleted_ids = []
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.
760
741
                    continue
761
 
            if exclude and is_inside_any(exclude, path):
762
 
                # Skip excluded paths. Excluded paths are processed by
763
 
                # _update_builder_with_changes.
764
 
                continue
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.
844
821
        else:
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)
851
826
        if delta:
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)
857
 
        if fs_hash:
858
 
            self.work_tree._observed_sha1(ie.file_id, path, fs_hash)
859
832
        return ie
860
833
 
861
834
    def _report_change(self, ie, path):