/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

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