~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commit.py

  • Committer: Alexander Belchenko
  • Date: 2007-09-22 17:29:16 UTC
  • mfrom: (2846 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2864.
  • Revision ID: bialix@ukr.net-20070922172916-yzl05wpf8ye852gw
Bug #140419 fixed by 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
241
242
                               " parameter is required for commit().")
242
243
 
243
244
        self.bound_branch = None
 
245
        self.any_entries_changed = False
 
246
        self.any_entries_deleted = False
244
247
        self.local = local
245
248
        self.master_branch = None
246
249
        self.master_locked = False
247
250
        self.rev_id = None
248
 
        self.specific_files = specific_files
 
251
        if specific_files is not None:
 
252
            self.specific_files = sorted(
 
253
                minimum_path_selection(specific_files))
 
254
        else:
 
255
            self.specific_files = None
 
256
        self.specific_file_ids = None
249
257
        self.allow_pointless = allow_pointless
250
258
        self.recursive = recursive
251
259
        self.revprops = revprops
280
288
                self.config = self.branch.get_config()
281
289
 
282
290
            # 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
 
291
            if self.specific_files is not None:
 
292
                # Note: This routine
285
293
                # is being called because it raises PathNotVerisonedError
286
 
                # as a side effect of finding the IDs.
 
294
                # as a side effect of finding the IDs. We later use the ids we
 
295
                # found as input to the working tree inventory iterator, so we
 
296
                # only consider those ids rather than examining the whole tree
 
297
                # again.
287
298
                # XXX: Dont we have filter_unversioned to do this more
288
299
                # cheaply?
289
 
                tree.find_ids_across_trees(specific_files,
290
 
                                           [self.basis_tree, self.work_tree])
 
300
                self.specific_file_ids = tree.find_ids_across_trees(
 
301
                    specific_files, [self.basis_tree, self.work_tree])
291
302
 
292
303
            # Setup the progress bar. As the number of files that need to be
293
304
            # committed in unknown, progress is reported as stages.
383
394
            return NullCommitReporter()
384
395
        return ReportCommitToLog()
385
396
 
386
 
    def _any_real_changes(self):
387
 
        """Are there real changes between new_inventory and basis?
388
 
 
389
 
        For trees without rich roots, inv.root.revision changes every commit.
390
 
        But if that is the only change, we want to treat it as though there
391
 
        are *no* changes.
392
 
        """
393
 
        new_entries = self.builder.new_inventory.iter_entries()
394
 
        basis_entries = self.basis_inv.iter_entries()
395
 
        new_path, new_root_ie = new_entries.next()
396
 
        basis_path, basis_root_ie = basis_entries.next()
397
 
 
398
 
        # This is a copy of InventoryEntry.__eq__ only leaving out .revision
399
 
        def ie_equal_no_revision(this, other):
400
 
            return ((this.file_id == other.file_id)
401
 
                    and (this.name == other.name)
402
 
                    and (this.symlink_target == other.symlink_target)
403
 
                    and (this.text_sha1 == other.text_sha1)
404
 
                    and (this.text_size == other.text_size)
405
 
                    and (this.text_id == other.text_id)
406
 
                    and (this.parent_id == other.parent_id)
407
 
                    and (this.kind == other.kind)
408
 
                    and (this.executable == other.executable)
409
 
                    and (this.reference_revision == other.reference_revision)
410
 
                    )
411
 
        if not ie_equal_no_revision(new_root_ie, basis_root_ie):
412
 
            return True
413
 
 
414
 
        for new_ie, basis_ie in zip(new_entries, basis_entries):
415
 
            if new_ie != basis_ie:
416
 
                return True
417
 
 
418
 
        # No actual changes present
419
 
        return False
420
 
 
421
397
    def _check_pointless(self):
422
398
        if self.allow_pointless:
423
399
            return
434
410
            return
435
411
        # If length == 1, then we only have the root entry. Which means
436
412
        # that there is no real difference (only the root could be different)
437
 
        if (len(self.builder.new_inventory) != 1 and self._any_real_changes()):
 
413
        if len(self.builder.new_inventory) != 1 and (self.any_entries_changed
 
414
            or self.any_entries_deleted):
438
415
            return
439
416
        raise PointlessCommit()
440
417
 
671
648
        # recorded in their previous state. For more details, see
672
649
        # https://lists.ubuntu.com/archives/bazaar/2007q3/028476.html.
673
650
        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:
 
651
            for path, old_ie in self.basis_inv.iter_entries():
 
652
                if old_ie.file_id in self.builder.new_inventory:
676
653
                    continue
677
654
                if is_inside_any(specific_files, path):
678
655
                    continue
679
 
                ie = new_ie.copy()
680
 
                ie.revision = None
681
 
                self.builder.record_entry_contents(ie, self.parent_invs, path,
682
 
                                                   self.basis_tree)
 
656
                if old_ie.kind == 'directory':
 
657
                    self._next_progress_entry()
 
658
                ie = old_ie.copy()
 
659
                # Note: specific file commits after a merge are currently
 
660
                # prohibited. This test is for sanity/safety in case it's
 
661
                # required after that changes.
 
662
                if len(self.parents) > 1:
 
663
                    ie.revision = None
 
664
                if self.builder.record_entry_contents(ie, self.parent_invs, path,
 
665
                    self.basis_tree):
 
666
                    self.any_entries_changed = True
683
667
 
 
668
        # note that deletes have occurred
 
669
        if set(self.basis_inv._byid.keys()) - set(self.builder.new_inventory._byid.keys()):
 
670
            self.any_entries_deleted = True
684
671
        # Report what was deleted.
685
 
        if self.reporter.is_verbose():
 
672
        if self.any_entries_deleted and self.reporter.is_verbose():
686
673
            for path, ie in self.basis_inv.iter_entries():
687
674
                if ie.file_id not in self.builder.new_inventory:
688
675
                    self.reporter.deleted(path)
699
686
        deleted_paths = set()
700
687
        work_inv = self.work_tree.inventory
701
688
        assert work_inv.root is not None
702
 
        entries = work_inv.iter_entries_by_dir()
 
689
        entries = work_inv.iter_entries_by_dir(
 
690
            specific_file_ids=self.specific_file_ids, yield_parents=True)
703
691
        if not self.builder.record_root_entry:
704
692
            entries.next()
705
693
        for path, existing_ie in entries:
709
697
            kind = existing_ie.kind
710
698
            if kind == 'directory':
711
699
                self._next_progress_entry()
712
 
 
713
700
            # Skip files that have been deleted from the working tree.
714
701
            # The deleted files/directories are also recorded so they
715
702
            # can be explicitly unversioned later. Note that when a
717
704
            # deleted files matching that filter.
718
705
            if is_inside_any(deleted_paths, path):
719
706
                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
 
707
            if not self.work_tree.has_filename(path):
 
708
                deleted_paths.add(path)
 
709
                self.reporter.missing(path)
 
710
                deleted_ids.append(file_id)
 
711
                continue
726
712
            try:
727
713
                kind = self.work_tree.kind(file_id)
728
714
                # TODO: specific_files filtering before nested tree processing
735
721
            # Note: I don't particularly want to have the existing_ie
736
722
            # parameter but the test suite currently (28-Jun-07) breaks
737
723
            # without it thanks to a unicode normalisation issue. :-(
738
 
            definitely_changed = kind != existing_ie.kind 
 
724
            definitely_changed = kind != existing_ie.kind
739
725
            self._record_entry(path, file_id, specific_files, kind, name,
740
726
                parent_id, definitely_changed, existing_ie, report_changes)
741
727
 
772
758
            report_changes=True):
773
759
        "Record the new inventory entry for a path if any."
774
760
        # 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
 
761
        # mutter('%s selected for commit', path)
 
762
        if definitely_changed or existing_ie is None:
 
763
            ie = inventory.make_entry(kind, name, parent_id, file_id)
783
764
        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)
 
765
            ie = existing_ie.copy()
 
766
            ie.revision = None
 
767
        if self.builder.record_entry_contents(ie, self.parent_invs, 
 
768
            path, self.work_tree):
 
769
            self.any_entries_changed = True
 
770
        if report_changes:
 
771
            self._report_change(ie, path)
795
772
        return ie
796
773
 
797
774
    def _report_change(self, ie, path):