/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/commit.py

  • Committer: Robert Collins
  • Date: 2007-07-25 00:52:21 UTC
  • mfrom: (2650 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2651.
  • Revision ID: robertc@robertcollins.net-20070725005221-0ysm6il5mqnme3wz
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
256
256
            # Check that the working tree is up to date
257
257
            old_revno,new_revno = self._check_out_of_date_tree()
258
258
 
259
 
            if strict:
260
 
                # raise an exception as soon as we find a single unknown.
261
 
                for unknown in self.work_tree.unknowns():
262
 
                    raise StrictCommitFailed()
263
 
                   
264
259
            if self.config is None:
265
260
                self.config = self.branch.get_config()
266
261
 
297
292
                raise errors.CannotCommitSelectedFileMerge(self.specific_files)
298
293
            
299
294
            # Collect the changes
300
 
            self._emit_progress_set_stage("Collecting changes", show_entries=True)
 
295
            self._set_progress_stage("Collecting changes",
 
296
                    entries_title="Directory")
301
297
            self.builder = self.branch.get_commit_builder(self.parents,
302
298
                self.config, timestamp, timezone, committer, revprops, rev_id)
303
299
            self._update_builder_with_changes()
307
303
            # ADHB 2006-08-08: If this is done, populate_new_inv should not add
308
304
            # weave lines, because nothing should be recorded until it is known
309
305
            # that commit will succeed.
310
 
            self._emit_progress_set_stage("Saving data locally")
 
306
            self._set_progress_stage("Saving data locally")
311
307
            self.builder.finish_inventory()
312
308
 
313
309
            # Prompt the user for a commit message if none provided
322
318
            # Upload revision data to the master.
323
319
            # this will propagate merged revisions too if needed.
324
320
            if self.bound_branch:
325
 
                self._emit_progress_set_stage("Uploading data to master branch")
 
321
                self._set_progress_stage("Uploading data to master branch")
326
322
                self.master_branch.repository.fetch(self.branch.repository,
327
323
                                                    revision_id=self.rev_id)
328
324
                # now the master has the revision data
335
331
            self.branch.set_last_revision_info(new_revno, self.rev_id)
336
332
 
337
333
            # Make the working tree up to date with the branch
338
 
            self._emit_progress_set_stage("Updating the working tree")
 
334
            self._set_progress_stage("Updating the working tree")
339
335
            rev_tree = self.builder.revision_tree()
340
336
            self.work_tree.set_parent_trees([(self.rev_id, rev_tree)])
341
337
            self.reporter.completed(new_revno, self.rev_id)
468
464
    def _process_hooks(self, old_revno, new_revno):
469
465
        """Process any registered commit hooks."""
470
466
        # Process the post commit hooks, if any
471
 
        self._emit_progress_set_stage("Running post commit hooks")
 
467
        self._set_progress_stage("Running post commit hooks")
472
468
        # old style commit hooks - should be deprecated ? (obsoleted in
473
469
        # 0.15)
474
470
        if self.config.post_commit() is not None:
594
590
 
595
591
        specific_files = self.specific_files
596
592
        mutter("Selecting files for commit with filter %s", specific_files)
597
 
        work_inv = self.work_tree.inventory
598
 
        assert work_inv.root is not None
599
 
        self.pb_entries_total = len(work_inv)
600
593
 
601
594
        # Check and warn about old CommitBuilders
602
 
        entries = work_inv.iter_entries()
603
595
        if not self.builder.record_root_entry:
604
596
            symbol_versioning.warn('CommitBuilders should support recording'
605
597
                ' the root entry as of bzr 0.10.', DeprecationWarning, 
606
598
                stacklevel=1)
607
599
            self.builder.new_inventory.add(self.basis_inv.root.copy())
608
 
            entries.next()
609
 
 
 
600
 
 
601
        # Build the new inventory
 
602
        self._populate_from_inventory(specific_files)
 
603
 
 
604
        # If specific files are selected, then all un-selected files must be
 
605
        # recorded in their previous state. For more details, see
 
606
        # https://lists.ubuntu.com/archives/bazaar/2007q3/028476.html.
 
607
        if specific_files:
 
608
            for path, new_ie in self.basis_inv.iter_entries():
 
609
                if new_ie.file_id in self.builder.new_inventory:
 
610
                    continue
 
611
                if is_inside_any(specific_files, path):
 
612
                    continue
 
613
                ie = new_ie.copy()
 
614
                ie.revision = None
 
615
                self.builder.record_entry_contents(ie, self.parent_invs, path,
 
616
                                                   self.basis_tree)
 
617
 
 
618
        # Report what was deleted. We could skip this when no deletes are
 
619
        # detected to gain a performance win, but it arguably serves as a
 
620
        # 'safety check' by informing the user whenever anything disappears.
 
621
        for path, ie in self.basis_inv.iter_entries():
 
622
            if ie.file_id not in self.builder.new_inventory:
 
623
                self.reporter.deleted(path)
 
624
 
 
625
    def _populate_from_inventory(self, specific_files):
 
626
        """Populate the CommitBuilder by walking the working tree inventory."""
 
627
        if self.strict:
 
628
            # raise an exception as soon as we find a single unknown.
 
629
            for unknown in self.work_tree.unknowns():
 
630
                raise StrictCommitFailed()
 
631
               
610
632
        deleted_ids = []
611
633
        deleted_paths = set()
612
 
        for path, new_ie in entries:
613
 
            self._emit_progress_next_entry()
614
 
            file_id = new_ie.file_id
 
634
        work_inv = self.work_tree.inventory
 
635
        assert work_inv.root is not None
 
636
        entries = work_inv.iter_entries()
 
637
        if not self.builder.record_root_entry:
 
638
            entries.next()
 
639
        for path, existing_ie in entries:
 
640
            file_id = existing_ie.file_id
 
641
            name = existing_ie.name
 
642
            parent_id = existing_ie.parent_id
 
643
            kind = existing_ie.kind
 
644
            if kind == 'directory':
 
645
                self._next_progress_entry()
615
646
 
616
647
            # Skip files that have been deleted from the working tree.
617
648
            # The deleted files/directories are also recorded so they
628
659
                    continue
629
660
            try:
630
661
                kind = self.work_tree.kind(file_id)
 
662
                # TODO: specific_files filtering before nested tree processing
631
663
                if kind == 'tree-reference' and self.recursive == 'down':
632
 
                    # nested tree: commit in it
633
 
                    sub_tree = WorkingTree.open(self.work_tree.abspath(path))
634
 
                    # FIXME: be more comprehensive here:
635
 
                    # this works when both trees are in --trees repository,
636
 
                    # but when both are bound to a different repository,
637
 
                    # it fails; a better way of approaching this is to 
638
 
                    # finally implement the explicit-caches approach design
639
 
                    # a while back - RBC 20070306.
640
 
                    if (sub_tree.branch.repository.bzrdir.root_transport.base
641
 
                        ==
642
 
                        self.work_tree.branch.repository.bzrdir.root_transport.base):
643
 
                        sub_tree.branch.repository = \
644
 
                            self.work_tree.branch.repository
645
 
                    try:
646
 
                        sub_tree.commit(message=None, revprops=self.revprops,
647
 
                            recursive=self.recursive,
648
 
                            message_callback=self.message_callback,
649
 
                            timestamp=self.timestamp, timezone=self.timezone,
650
 
                            committer=self.committer,
651
 
                            allow_pointless=self.allow_pointless,
652
 
                            strict=self.strict, verbose=self.verbose,
653
 
                            local=self.local, reporter=self.reporter)
654
 
                    except errors.PointlessCommit:
655
 
                        pass
656
 
                if kind != new_ie.kind:
657
 
                    new_ie = inventory.make_entry(kind, new_ie.name,
658
 
                                                  new_ie.parent_id, file_id)
 
664
                    self._commit_nested_tree(file_id, path)
659
665
            except errors.NoSuchFile:
660
666
                pass
661
 
            # mutter('check %s {%s}', path, file_id)
662
 
            if (not specific_files or 
663
 
                is_inside_or_parent_of_any(specific_files, path)):
664
 
                    # mutter('%s selected for commit', path)
665
 
                    ie = new_ie.copy()
 
667
 
 
668
            # Record an entry for this item
 
669
            # Note: I don't particularly want to have the existing_ie
 
670
            # parameter but the test suite currently (28-Jun-07) breaks
 
671
            # without it thanks to a unicode normalisation issue. :-(
 
672
            definitely_changed = kind != existing_ie.kind 
 
673
            self._record_entry(path, file_id, specific_files, kind, name,
 
674
                parent_id, definitely_changed, existing_ie)
 
675
 
 
676
        # Unversion IDs that were found to be deleted
 
677
        self.work_tree.unversion(deleted_ids)
 
678
 
 
679
    def _commit_nested_tree(self, file_id, path):
 
680
        "Commit a nested tree."
 
681
        sub_tree = self.work_tree.get_nested_tree(file_id, path)
 
682
        # FIXME: be more comprehensive here:
 
683
        # this works when both trees are in --trees repository,
 
684
        # but when both are bound to a different repository,
 
685
        # it fails; a better way of approaching this is to 
 
686
        # finally implement the explicit-caches approach design
 
687
        # a while back - RBC 20070306.
 
688
        if (sub_tree.branch.repository.bzrdir.root_transport.base
 
689
            ==
 
690
            self.work_tree.branch.repository.bzrdir.root_transport.base):
 
691
            sub_tree.branch.repository = \
 
692
                self.work_tree.branch.repository
 
693
        try:
 
694
            sub_tree.commit(message=None, revprops=self.revprops,
 
695
                recursive=self.recursive,
 
696
                message_callback=self.message_callback,
 
697
                timestamp=self.timestamp, timezone=self.timezone,
 
698
                committer=self.committer,
 
699
                allow_pointless=self.allow_pointless,
 
700
                strict=self.strict, verbose=self.verbose,
 
701
                local=self.local, reporter=self.reporter)
 
702
        except errors.PointlessCommit:
 
703
            pass
 
704
 
 
705
    def _record_entry(self, path, file_id, specific_files, kind, name,
 
706
                      parent_id, definitely_changed, existing_ie=None):
 
707
        "Record the new inventory entry for a path if any."
 
708
        # mutter('check %s {%s}', path, file_id)
 
709
        if (not specific_files or 
 
710
            is_inside_or_parent_of_any(specific_files, path)):
 
711
                # mutter('%s selected for commit', path)
 
712
                if definitely_changed or existing_ie is None:
 
713
                    ie = inventory.make_entry(kind, name, parent_id, file_id)
 
714
                else:
 
715
                    ie = existing_ie.copy()
666
716
                    ie.revision = None
 
717
        else:
 
718
            # mutter('%s not selected for commit', path)
 
719
            if self.basis_inv.has_id(file_id):
 
720
                ie = self.basis_inv[file_id].copy()
667
721
            else:
668
 
                # mutter('%s not selected for commit', path)
669
 
                if self.basis_inv.has_id(file_id):
670
 
                    ie = self.basis_inv[file_id].copy()
671
 
                else:
672
 
                    # this entry is new and not being committed
673
 
                    continue
 
722
                # this entry is new and not being committed
 
723
                ie = None
 
724
        if ie is not None:
674
725
            self.builder.record_entry_contents(ie, self.parent_invs, 
675
726
                path, self.work_tree)
676
 
            # describe the nature of the change that has occurred relative to
677
 
            # the basis inventory.
678
 
            if (self.basis_inv.has_id(ie.file_id)):
679
 
                basis_ie = self.basis_inv[ie.file_id]
680
 
            else:
681
 
                basis_ie = None
682
 
            change = ie.describe_change(basis_ie, ie)
683
 
            if change in (InventoryEntry.RENAMED, 
684
 
                InventoryEntry.MODIFIED_AND_RENAMED):
685
 
                old_path = self.basis_inv.id2path(ie.file_id)
686
 
                self.reporter.renamed(change, old_path, path)
687
 
            else:
688
 
                self.reporter.snapshot_change(change, path)
689
 
 
690
 
        # Unversion IDs that were found to be deleted
691
 
        self.work_tree.unversion(deleted_ids)
692
 
 
693
 
        # If specific files/directories were nominated, it is possible
694
 
        # that some data from outside those needs to be preserved from
695
 
        # the basis tree. For example, if a file x is moved from out of
696
 
        # directory foo into directory bar and the user requests
697
 
        # ``commit foo``, then information about bar/x must also be
698
 
        # recorded.
699
 
        if specific_files:
700
 
            for path, new_ie in self.basis_inv.iter_entries():
701
 
                if new_ie.file_id in work_inv:
702
 
                    continue
703
 
                if is_inside_any(specific_files, path):
704
 
                    continue
705
 
                ie = new_ie.copy()
706
 
                ie.revision = None
707
 
                self.builder.record_entry_contents(ie, self.parent_invs, path,
708
 
                                                   self.basis_tree)
709
 
 
710
 
        # Report what was deleted. We could skip this when no deletes are
711
 
        # detected to gain a performance win, but it arguably serves as a
712
 
        # 'safety check' by informing the user whenever anything disappears.
713
 
        for path, ie in self.basis_inv.iter_entries():
714
 
            if ie.file_id not in self.builder.new_inventory:
715
 
                self.reporter.deleted(path)
716
 
 
717
 
    def _emit_progress_set_stage(self, name, show_entries=False):
 
727
            self._report_change(ie, path)
 
728
        return ie
 
729
 
 
730
    def _report_change(self, ie, path):
 
731
        """Report a change to the user.
 
732
 
 
733
        The change that has occurred is described relative to the basis
 
734
        inventory.
 
735
        """
 
736
        if (self.basis_inv.has_id(ie.file_id)):
 
737
            basis_ie = self.basis_inv[ie.file_id]
 
738
        else:
 
739
            basis_ie = None
 
740
        change = ie.describe_change(basis_ie, ie)
 
741
        if change in (InventoryEntry.RENAMED, 
 
742
            InventoryEntry.MODIFIED_AND_RENAMED):
 
743
            old_path = self.basis_inv.id2path(ie.file_id)
 
744
            self.reporter.renamed(change, old_path, path)
 
745
        else:
 
746
            self.reporter.snapshot_change(change, path)
 
747
 
 
748
    def _set_progress_stage(self, name, entries_title=None):
718
749
        """Set the progress stage and emit an update to the progress bar."""
719
750
        self.pb_stage_name = name
720
751
        self.pb_stage_count += 1
721
 
        self.pb_entries_show = show_entries
722
 
        if show_entries:
 
752
        self.pb_entries_title = entries_title
 
753
        if entries_title is not None:
723
754
            self.pb_entries_count = 0
724
755
            self.pb_entries_total = '?'
725
756
        self._emit_progress()
726
757
 
727
 
    def _emit_progress_next_entry(self):
728
 
        """Emit an update to the progress bar and increment the file count."""
 
758
    def _next_progress_entry(self):
 
759
        """Emit an update to the progress bar and increment the entry count."""
729
760
        self.pb_entries_count += 1
730
761
        self._emit_progress()
731
762
 
732
763
    def _emit_progress(self):
733
 
        if self.pb_entries_show:
734
 
            text = "%s [Entry %d/%s] - Stage" % (self.pb_stage_name,
735
 
                self.pb_entries_count,str(self.pb_entries_total))
 
764
        if self.pb_entries_title:
 
765
            if self.pb_entries_total == '?':
 
766
                text = "%s [%s %d] - Stage" % (self.pb_stage_name,
 
767
                    self.pb_entries_title, self.pb_entries_count)
 
768
            else:
 
769
                text = "%s [%s %d/%s] - Stage" % (self.pb_stage_name,
 
770
                    self.pb_entries_title, self.pb_entries_count,
 
771
                    str(self.pb_entries_total))
736
772
        else:
737
773
            text = "%s - Stage" % (self.pb_stage_name)
738
774
        self.pb.update(text, self.pb_stage_count, self.pb_stage_total)