/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: 2009-03-13 02:25:46 UTC
  • mfrom: (4133 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4183.
  • Revision ID: robertc@robertcollins.net-20090313022546-e7de5zsdkbay5okf
MergeĀ .dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
60
60
    debug,
61
61
    errors,
62
62
    revision,
 
63
    trace,
63
64
    tree,
64
65
    )
65
66
from bzrlib.branch import Branch
77
78
                            )
78
79
from bzrlib.testament import Testament
79
80
from bzrlib.trace import mutter, note, warning, is_quiet
80
 
from bzrlib.inventory import InventoryEntry, make_entry
 
81
from bzrlib.inventory import Inventory, InventoryEntry, make_entry
81
82
from bzrlib import symbol_versioning
82
83
from bzrlib.symbol_versioning import (deprecated_passed,
83
84
        deprecated_function,
205
206
               config=None,
206
207
               message_callback=None,
207
208
               recursive='down',
208
 
               exclude=None):
 
209
               exclude=None,
 
210
               possible_master_transports=None):
209
211
        """Commit working copy as a new revision.
210
212
 
211
213
        :param message: the commit message (it or message_callback is required)
235
237
            pending changes of any sort during this commit.
236
238
        :param exclude: None or a list of relative paths to exclude from the
237
239
            commit. Pending changes to excluded files will be ignored by the
238
 
            commit. 
 
240
            commit.
239
241
        """
240
242
        mutter('preparing to commit')
241
243
 
294
296
                raise ConflictsInTree
295
297
 
296
298
            # Setup the bound branch variables as needed.
297
 
            self._check_bound_branch()
 
299
            self._check_bound_branch(possible_master_transports)
298
300
 
299
301
            # Check that the working tree is up to date
300
302
            old_revno, new_revno = self._check_out_of_date_tree()
349
351
                    entries_title="Directory")
350
352
            self.builder = self.branch.get_commit_builder(self.parents,
351
353
                self.config, timestamp, timezone, committer, revprops, rev_id)
352
 
            
 
354
 
353
355
            try:
354
 
                self.builder.recording_deletes()
 
356
                self.builder.will_record_deletes()
355
357
                # find the location being committed to
356
358
                if self.bound_branch:
357
359
                    master_location = self.master_branch.base
380
382
                # Add revision data to the local branch
381
383
                self.rev_id = self.builder.commit(self.message)
382
384
 
383
 
            except:
 
385
            except Exception, e:
 
386
                mutter("aborting commit write group because of exception:")
 
387
                trace.log_exception_quietly()
 
388
                note("aborting commit write group: %r" % (e,))
384
389
                self.builder.abort()
385
390
                raise
386
391
 
389
394
            # Upload revision data to the master.
390
395
            # this will propagate merged revisions too if needed.
391
396
            if self.bound_branch:
392
 
                if not self.master_branch.repository.has_same_location(
393
 
                        self.branch.repository):
394
 
                    self._set_progress_stage("Uploading data to master branch")
395
 
                    self.master_branch.repository.fetch(self.branch.repository,
396
 
                        revision_id=self.rev_id)
397
 
                # now the master has the revision data
 
397
                self._set_progress_stage("Uploading data to master branch")
398
398
                # 'commit' to the master first so a timeout here causes the
399
399
                # local branch to be out of date
400
 
                self.master_branch.set_last_revision_info(new_revno,
401
 
                                                          self.rev_id)
 
400
                self.master_branch.import_last_revision_info(
 
401
                    self.branch.repository, new_revno, self.rev_id)
402
402
 
403
403
            # and now do the commit locally.
404
404
            self.branch.set_last_revision_info(new_revno, self.rev_id)
406
406
            # Make the working tree up to date with the branch
407
407
            self._set_progress_stage("Updating the working tree")
408
408
            self.work_tree.update_basis_by_delta(self.rev_id,
409
 
                 self.builder.basis_delta)
 
409
                 self.builder.get_basis_delta())
410
410
            self.reporter.completed(new_revno, self.rev_id)
411
411
            self._process_post_hooks(old_revno, new_revno)
412
412
        finally:
435
435
        # If length == 1, then we only have the root entry. Which means
436
436
        # that there is no real difference (only the root could be different)
437
437
        # unless deletes occured, in which case the length is irrelevant.
438
 
        if (self.any_entries_deleted or 
 
438
        if (self.any_entries_deleted or
439
439
            (len(self.builder.new_inventory) != 1 and
440
440
             self.builder.any_changes())):
441
441
            return
442
442
        raise PointlessCommit()
443
443
 
444
 
    def _check_bound_branch(self):
 
444
    def _check_bound_branch(self, possible_master_transports=None):
445
445
        """Check to see if the local branch is bound.
446
446
 
447
447
        If it is bound, then most of the commit will actually be
452
452
            raise errors.LocalRequiresBoundBranch()
453
453
 
454
454
        if not self.local:
455
 
            self.master_branch = self.branch.get_master_branch()
 
455
            self.master_branch = self.branch.get_master_branch(
 
456
                possible_master_transports)
456
457
 
457
458
        if not self.master_branch:
458
459
            # make this branch the reference branch for out of date checks.
469
470
        #       commits to the remote branch if they would fit.
470
471
        #       But for now, just require remote to be identical
471
472
        #       to local.
472
 
        
 
473
 
473
474
        # Make sure the local branch is identical to the master
474
475
        master_info = self.master_branch.last_revision_info()
475
476
        local_info = self.branch.last_revision_info()
532
533
    def _process_hooks(self, hook_name, old_revno, new_revno):
533
534
        if not Branch.hooks[hook_name]:
534
535
            return
535
 
        
 
536
 
536
537
        # new style commit hooks:
537
538
        if not self.bound_branch:
538
539
            hook_master = self.branch
547
548
            old_revid = self.parents[0]
548
549
        else:
549
550
            old_revid = bzrlib.revision.NULL_REVISION
550
 
        
 
551
 
551
552
        if hook_name == "pre_commit":
552
553
            future_tree = self.builder.revision_tree()
553
554
            tree_delta = future_tree.changes_from(self.basis_tree,
554
555
                                             include_root=True)
555
 
        
 
556
 
556
557
        for hook in Branch.hooks[hook_name]:
557
558
            # show the running hook in the progress bar. As hooks may
558
559
            # end up doing nothing (e.g. because they are not configured by
588
589
            # typically this will be useful enough.
589
590
            except Exception, e:
590
591
                found_exception = e
591
 
        if found_exception is not None: 
 
592
        if found_exception is not None:
592
593
            # don't do a plan raise, because the last exception may have been
593
594
            # trashed, e is our sure-to-work exception even though it loses the
594
595
            # full traceback. XXX: RBC 20060421 perhaps we could check the
595
 
            # exc_info and if its the same one do a plain raise otherwise 
 
596
            # exc_info and if its the same one do a plain raise otherwise
596
597
            # 'raise e' as we do now.
597
598
            raise e
598
599
 
614
615
        # serialiser not by commit. Then we can also add an unescaper
615
616
        # in the deserializer and start roundtripping revision messages
616
617
        # precisely. See repository_implementations/test_repository.py
617
 
        
 
618
 
618
619
        # Python strings can include characters that can't be
619
620
        # represented in well-formed XML; escape characters that
620
621
        # aren't listed in the XML specification
628
629
 
629
630
    def _gather_parents(self):
630
631
        """Record the parents of a merge for merge detection."""
631
 
        # TODO: Make sure that this list doesn't contain duplicate 
 
632
        # TODO: Make sure that this list doesn't contain duplicate
632
633
        # entries and the order is preserved when doing this.
633
634
        self.parents = self.work_tree.get_parent_ids()
634
635
        self.parent_invs = [self.basis_inv]
647
648
        #
648
649
        # This starts by creating a new empty inventory. Depending on
649
650
        # which files are selected for commit, and what is present in the
650
 
        # current tree, the new inventory is populated. inventory entries 
 
651
        # current tree, the new inventory is populated. inventory entries
651
652
        # which are candidates for modification have their revision set to
652
653
        # None; inventory entries that are carried over untouched have their
653
654
        # revision set to their prior value.
693
694
    def _report_and_accumulate_deletes(self):
694
695
        # XXX: Could the list of deleted paths and ids be instead taken from
695
696
        # _populate_from_inventory?
696
 
        deleted_ids = set(self.basis_inv._byid.keys()) - \
697
 
            set(self.builder.new_inventory._byid.keys())
 
697
        if (isinstance(self.basis_inv, Inventory)
 
698
            and isinstance(self.builder.new_inventory, Inventory)):
 
699
            # the older Inventory classes provide a _byid dict, and building a
 
700
            # set from the keys of this dict is substantially faster than even
 
701
            # getting a set of ids from the inventory
 
702
            #
 
703
            # <lifeless> set(dict) is roughly the same speed as
 
704
            # set(iter(dict)) and both are significantly slower than
 
705
            # set(dict.keys())
 
706
            deleted_ids = set(self.basis_inv._byid.keys()) - \
 
707
               set(self.builder.new_inventory._byid.keys())
 
708
        else:
 
709
            deleted_ids = set(self.basis_inv) - set(self.builder.new_inventory)
698
710
        if deleted_ids:
699
711
            self.any_entries_deleted = True
700
712
            deleted = [(self.basis_tree.id2path(file_id), file_id)
711
723
            # raise an exception as soon as we find a single unknown.
712
724
            for unknown in self.work_tree.unknowns():
713
725
                raise StrictCommitFailed()
714
 
        
 
726
 
715
727
        specific_files = self.specific_files
716
728
        exclude = self.exclude
717
729
        report_changes = self.reporter.is_verbose()
807
819
        # FIXME: be more comprehensive here:
808
820
        # this works when both trees are in --trees repository,
809
821
        # but when both are bound to a different repository,
810
 
        # it fails; a better way of approaching this is to 
 
822
        # it fails; a better way of approaching this is to
811
823
        # finally implement the explicit-caches approach design
812
824
        # a while back - RBC 20070306.
813
825
        if sub_tree.branch.repository.has_same_location(
858
870
        else:
859
871
            basis_ie = None
860
872
        change = ie.describe_change(basis_ie, ie)
861
 
        if change in (InventoryEntry.RENAMED, 
 
873
        if change in (InventoryEntry.RENAMED,
862
874
            InventoryEntry.MODIFIED_AND_RENAMED):
863
875
            old_path = self.basis_inv.id2path(ie.file_id)
864
876
            self.reporter.renamed(change, old_path, path)