~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commit.py

  • Committer: Robert Collins
  • Date: 2007-09-20 07:03:33 UTC
  • mto: (2843.1.1 ianc-integration2)
  • mto: This revision was merged to the branch mainline in revision 2844.
  • Revision ID: robertc@robertcollins.net-20070920070333-eedxrxidkignx4i1
* Partial commits are now approximately 40% faster by walking over the
  unselected current tree more efficiently. (Robert Collins)

* New method ``bzrlib.osutils.minimum_path_selection`` useful for removing
  duplication from user input, when a user mentions both a path and an item
  contained within that path. (Robert Collins)

* New parameter yield_parents on ``Inventory.iter_entries_by_dir`` which
  causes the parents of a selected id to be returned recursively, so all the
  paths from the root down to each element of selected_file_ids are
  returned. (Robert Collins)

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 (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
245
246
        self.master_branch = None
246
247
        self.master_locked = False
247
248
        self.rev_id = None
248
 
        self.specific_files = specific_files
 
249
        self.specific_files = sorted(
 
250
            minimum_path_selection(specific_files or ()))
 
251
        self.specific_file_ids = None
249
252
        self.allow_pointless = allow_pointless
250
253
        self.recursive = recursive
251
254
        self.revprops = revprops
280
283
                self.config = self.branch.get_config()
281
284
 
282
285
            # If provided, ensure the specified files are versioned
283
 
            if specific_files is not None:
284
 
                # Note: We don't actually need the IDs here. This routine
 
286
            if self.specific_files:
 
287
                # Note: This routine
285
288
                # is being called because it raises PathNotVerisonedError
286
 
                # as a side effect of finding the IDs.
 
289
                # as a side effect of finding the IDs. We later use the ids we
 
290
                # found as input to the workng tree inventory iterator, so we
 
291
                # only consider those ids rather than examining the whole tree
 
292
                # again.
287
293
                # XXX: Dont we have filter_unversioned to do this more
288
294
                # cheaply?
289
 
                tree.find_ids_across_trees(specific_files,
290
 
                                           [self.basis_tree, self.work_tree])
 
295
                self.specific_file_ids = tree.find_ids_across_trees(
 
296
                    specific_files, [self.basis_tree, self.work_tree])
291
297
 
292
298
            # Setup the progress bar. As the number of files that need to be
293
299
            # committed in unknown, progress is reported as stages.
671
677
        # recorded in their previous state. For more details, see
672
678
        # https://lists.ubuntu.com/archives/bazaar/2007q3/028476.html.
673
679
        if specific_files:
674
 
            for path, new_ie in self.basis_inv.iter_entries():
675
 
                if new_ie.file_id in self.builder.new_inventory:
 
680
            for path, old_ie in self.basis_inv.iter_entries():
 
681
                if old_ie.file_id in self.builder.new_inventory:
676
682
                    continue
677
683
                if is_inside_any(specific_files, path):
678
684
                    continue
679
 
                ie = new_ie.copy()
680
 
                ie.revision = None
 
685
                if old_ie.kind == 'directory':
 
686
                    self._next_progress_entry()
 
687
                ie = old_ie.copy()
681
688
                self.builder.record_entry_contents(ie, self.parent_invs, path,
682
689
                                                   self.basis_tree)
683
690
 
699
706
        deleted_paths = set()
700
707
        work_inv = self.work_tree.inventory
701
708
        assert work_inv.root is not None
702
 
        entries = work_inv.iter_entries()
 
709
        entries = work_inv.iter_entries_by_dir(
 
710
            specific_file_ids=self.specific_file_ids, yield_parents=True)
703
711
        if not self.builder.record_root_entry:
704
712
            entries.next()
705
713
        for path, existing_ie in entries:
709
717
            kind = existing_ie.kind
710
718
            if kind == 'directory':
711
719
                self._next_progress_entry()
712
 
 
713
720
            # Skip files that have been deleted from the working tree.
714
721
            # The deleted files/directories are also recorded so they
715
722
            # can be explicitly unversioned later. Note that when a
717
724
            # deleted files matching that filter.
718
725
            if is_inside_any(deleted_paths, path):
719
726
                continue
720
 
            if not specific_files or is_inside_any(specific_files, path):
721
 
                if not self.work_tree.has_filename(path):
722
 
                    deleted_paths.add(path)
723
 
                    self.reporter.missing(path)
724
 
                    deleted_ids.append(file_id)
725
 
                    continue
 
727
            if not self.work_tree.has_filename(path):
 
728
                deleted_paths.add(path)
 
729
                self.reporter.missing(path)
 
730
                deleted_ids.append(file_id)
 
731
                continue
726
732
            try:
727
733
                kind = self.work_tree.kind(file_id)
728
734
                # TODO: specific_files filtering before nested tree processing
772
778
            report_changes=True):
773
779
        "Record the new inventory entry for a path if any."
774
780
        # mutter('check %s {%s}', path, file_id)
775
 
        if (not specific_files or 
776
 
            is_inside_or_parent_of_any(specific_files, path)):
777
 
                # mutter('%s selected for commit', path)
778
 
                if definitely_changed or existing_ie is None:
779
 
                    ie = inventory.make_entry(kind, name, parent_id, file_id)
780
 
                else:
781
 
                    ie = existing_ie.copy()
782
 
                    ie.revision = None
 
781
        # mutter('%s selected for commit', path)
 
782
        if definitely_changed or existing_ie is None:
 
783
            ie = inventory.make_entry(kind, name, parent_id, file_id)
783
784
        else:
784
 
            # mutter('%s not selected for commit', path)
785
 
            if self.basis_inv.has_id(file_id):
786
 
                ie = self.basis_inv[file_id].copy()
787
 
            else:
788
 
                # this entry is new and not being committed
789
 
                ie = None
790
 
        if ie is not None:
791
 
            self.builder.record_entry_contents(ie, self.parent_invs, 
792
 
                path, self.work_tree)
793
 
            if report_changes:
794
 
                self._report_change(ie, path)
 
785
            ie = existing_ie.copy()
 
786
            ie.revision = None
 
787
        self.builder.record_entry_contents(ie, self.parent_invs, 
 
788
            path, self.work_tree)
 
789
        if report_changes:
 
790
            self._report_change(ie, path)
795
791
        return ie
796
792
 
797
793
    def _report_change(self, ie, path):