/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/workingtree.py

Merge bzr.dev and fully converted uses of new parents api.

Show diffs side-by-side

added added

removed removed

Lines of Context:
322
322
        self.branch.break_lock()
323
323
 
324
324
    def _set_inventory(self, inv):
 
325
        assert inv.root is not None
325
326
        self._inventory = inv
326
327
        self.path2id = self._inventory.path2id
327
328
 
393
394
        return pathjoin(self.basedir, filename)
394
395
    
395
396
    def basis_tree(self):
396
 
        """Return RevisionTree for the current last revision."""
 
397
        """Return RevisionTree for the current last revision.
 
398
        
 
399
        If the left most parent is a ghost then the returned tree will be an
 
400
        empty tree - one obtained by calling repository.revision_tree(None).
 
401
        """
397
402
        revision_id = self.last_revision()
398
403
        if revision_id is not None:
399
404
            try:
400
405
                xml = self.read_basis_inventory()
401
406
                inv = bzrlib.xml5.serializer_v5.read_inventory_from_string(xml)
 
407
                inv.root.revision = revision_id
402
408
            except NoSuchFile:
403
409
                inv = None
404
410
            if inv is not None and inv.revision_id == revision_id:
405
411
                return bzrlib.tree.RevisionTree(self.branch.repository, inv,
406
412
                                                revision_id)
407
413
        # FIXME? RBC 20060403 should we cache the inventory here ?
408
 
        return self.branch.repository.revision_tree(revision_id)
 
414
        try:
 
415
            return self.branch.repository.revision_tree(revision_id)
 
416
        except errors.RevisionNotPresent:
 
417
            # the basis tree *may* be a ghost or a low level error may have
 
418
            # occured. If the revision is present, its a problem, if its not
 
419
            # its a ghost.
 
420
            if self.branch.repository.has_revision(revision_id):
 
421
                raise
 
422
            # the basis tree is a ghost so return an empty tree.
 
423
            return self.branch.repository.revision_tree(None)
409
424
 
410
425
    @staticmethod
411
426
    @deprecated_method(zero_eight)
476
491
            parents = []
477
492
        else:
478
493
            parents = [last_rev]
479
 
        other_parents = self.pending_merges()
480
 
        return parents + other_parents
 
494
        try:
 
495
            merges_file = self._control_files.get_utf8('pending-merges')
 
496
        except NoSuchFile:
 
497
            pass
 
498
        else:
 
499
            for l in merges_file.readlines():
 
500
                parents.append(l.rstrip('\n'))
 
501
        return parents
481
502
 
482
503
    def get_root_id(self):
483
504
        """Return the id of this trees root"""
643
664
        self._write_inventory(inv)
644
665
 
645
666
    @needs_write_lock
646
 
    def add_parent_tree_id(self, revision_id):
 
667
    def add_parent_tree_id(self, revision_id, allow_leftmost_as_ghost=False):
647
668
        """Add revision_id as a parent.
648
669
 
649
670
        This is equivalent to retrieving the current list of parent ids
650
671
        and setting the list to its value plus revision_id.
651
672
 
652
673
        :param revision_id: The revision id to add to the parent list. It may
653
 
        be a ghost revision.
 
674
        be a ghost revision as long as its not the first parent to be added,
 
675
        or the allow_leftmost_as_ghost parameter is set True.
 
676
        :param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
654
677
        """
655
 
        self.set_parent_ids(self.get_parent_ids() + [revision_id])
 
678
        parents = self.get_parent_ids() + [revision_id]
 
679
        self.set_parent_ids(parents,
 
680
            allow_leftmost_as_ghost=len(parents) > 1 or allow_leftmost_as_ghost)
656
681
 
657
682
    @needs_write_lock
658
 
    def add_parent_tree(self, parent_tuple):
 
683
    def add_parent_tree(self, parent_tuple, allow_leftmost_as_ghost=False):
659
684
        """Add revision_id, tree tuple as a parent.
660
685
 
661
686
        This is equivalent to retrieving the current list of parent trees
664
689
        simpler to use that api. If you have the parent already available, using
665
690
        this api is preferred.
666
691
 
667
 
        :param parent_tuple: The (revision id, tree) to add to the parent list.             If the revision_id is a ghost, pass None for the tree.
 
692
        :param parent_tuple: The (revision id, tree) to add to the parent list.
 
693
            If the revision_id is a ghost, pass None for the tree.
 
694
        :param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
668
695
        """
669
 
        self.set_parent_ids(self.get_parent_ids() + [parent_tuple[0]])
 
696
        self.set_parent_ids(self.get_parent_ids() + [parent_tuple[0]],
 
697
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
670
698
 
671
699
    @needs_write_lock
672
700
    def add_pending_merge(self, *revision_ids):
673
701
        # TODO: Perhaps should check at this point that the
674
702
        # history of the revision is actually present?
675
 
        p = self.pending_merges()
 
703
        parents = self.get_parent_ids()
676
704
        updated = False
677
705
        for rev_id in revision_ids:
678
 
            if rev_id in p:
 
706
            if rev_id in parents:
679
707
                continue
680
 
            p.append(rev_id)
 
708
            parents.append(rev_id)
681
709
            updated = True
682
710
        if updated:
683
 
            self.set_pending_merges(p)
 
711
            self.set_parent_ids(parents, allow_leftmost_as_ghost=True)
684
712
 
685
713
    @needs_read_lock
686
714
    def pending_merges(self):
689
717
        These are revisions that have been merged into the working
690
718
        directory but not yet committed.
691
719
        """
692
 
        try:
693
 
            merges_file = self._control_files.get_utf8('pending-merges')
694
 
        except NoSuchFile:
695
 
            return []
696
 
        p = []
697
 
        for l in merges_file.readlines():
698
 
            p.append(l.rstrip('\n'))
699
 
        return p
 
720
        return self.get_parent_ids()[1:]
700
721
 
701
722
    @needs_write_lock
702
 
    def set_parent_ids(self, revision_ids):
 
723
    def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
703
724
        """Set the parent ids to revision_ids.
704
725
        
705
726
        See also set_parent_trees. This api will try to retrieve the tree data
711
732
        :param revision_ids: The revision_ids to set as the parent ids of this
712
733
            working tree. Any of these may be ghosts.
713
734
        """
714
 
        trees = []
715
 
        for rev_id in revision_ids:
716
 
            try:
717
 
                trees.append(
718
 
                    (rev_id, self.branch.repository.revision_tree(rev_id)))
719
 
            except errors.RevisionNotPresent:
720
 
                trees.append((rev_id, None))
721
 
                pass
722
 
        self.set_parent_trees(trees)
 
735
        if len(revision_ids) > 0:
 
736
            leftmost_id = revision_ids[0]
 
737
            if (not allow_leftmost_as_ghost and not
 
738
                self.branch.repository.has_revision(leftmost_id)):
 
739
                raise errors.GhostRevisionUnusableHere(leftmost_id)
 
740
            self.set_last_revision(leftmost_id)
 
741
        else:
 
742
            self.set_last_revision(None)
 
743
        merges = revision_ids[1:]
 
744
        self._control_files.put_utf8('pending-merges', '\n'.join(merges))
723
745
 
724
746
    @needs_write_lock
725
 
    def set_parent_trees(self, parents_list):
 
747
    def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
726
748
        """Set the parents of the working tree.
727
749
 
728
750
        :param parents_list: A list of (revision_id, tree) tuples. 
729
751
            If tree is None, then that element is treated as an unreachable
730
752
            parent tree - i.e. a ghost.
731
753
        """
732
 
        parent = parents_list[:1]
733
 
        if len(parent):
734
 
            self.set_last_revision(parent[0][0])
735
 
        else:
736
 
            self.set_last_revision(None)
737
 
        merges = parents_list[1:]
738
 
        self.set_pending_merges([revid for revid, tree in merges])
 
754
        # parent trees are not used in current format trees, delegate to
 
755
        # set_parent_ids
 
756
        self.set_parent_ids([rev for (rev, tree) in parents_list],
 
757
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
739
758
 
740
759
    @needs_write_lock
741
760
    def set_pending_merges(self, rev_list):
742
 
        self._control_files.put_utf8('pending-merges', '\n'.join(rev_list))
 
761
        parents = self.get_parent_ids()
 
762
        leftmost = parents[:1]
 
763
        new_parents = leftmost + rev_list
 
764
        self.set_parent_ids(new_parents)
743
765
 
744
766
    @needs_write_lock
745
767
    def set_merge_modified(self, modified_hashes):
923
945
        if to_dir_id == None and to_name != '':
924
946
            raise BzrError("destination %r is not a versioned directory" % to_name)
925
947
        to_dir_ie = inv[to_dir_id]
926
 
        if to_dir_ie.kind not in ('directory', 'root_directory'):
 
948
        if to_dir_ie.kind != 'directory':
927
949
            raise BzrError("destination %r is not a directory" % to_abs)
928
950
 
929
951
        to_idpath = inv.get_idpath(to_dir_id)
1239
1261
        for regex, mapping in rules:
1240
1262
            match = regex.match(filename)
1241
1263
            if match is not None:
1242
 
                # one or more of the groups in mapping will have a non-None group 
1243
 
                # match.
 
1264
                # one or more of the groups in mapping will have a non-None
 
1265
                # group match.
1244
1266
                groups = match.groups()
1245
1267
                rules = [mapping[group] for group in 
1246
1268
                    mapping if groups[group] is not None]
1402
1424
            old_tree = self.basis_tree()
1403
1425
        conflicts = revert(self, old_tree, filenames, backups, pb)
1404
1426
        if not len(filenames):
1405
 
            self.set_pending_merges([])
 
1427
            self.set_parent_ids(self.get_parent_ids()[:1])
1406
1428
            resolve(self)
1407
1429
        else:
1408
1430
            resolve(self, filenames, ignore_misses=True)
1479
1501
        Do a 'normal' merge of the old branch basis if it is relevant.
1480
1502
        """
1481
1503
        old_tip = self.branch.update()
1482
 
        if old_tip is not None:
1483
 
            self.add_pending_merge(old_tip)
1484
 
        self.branch.lock_read()
1485
 
        try:
1486
 
            result = 0
1487
 
            if self.last_revision() != self.branch.last_revision():
1488
 
                # merge tree state up to new branch tip.
1489
 
                basis = self.basis_tree()
1490
 
                to_tree = self.branch.basis_tree()
1491
 
                result += merge_inner(self.branch,
1492
 
                                      to_tree,
1493
 
                                      basis,
1494
 
                                      this_tree=self)
1495
 
                self.set_last_revision(self.branch.last_revision())
1496
 
                # TODO - dedup parents list with things merged by pull ?
1497
 
                # reuse the tree we've updated to to set the basis:
1498
 
                parent_trees = [(self.branch.last_revision(), to_tree)]
1499
 
                merges = self.get_parent_ids()[1:]
1500
 
                # pull the other trees out of the repository. This could be
1501
 
                # better expressed - for instance by inserting a parent, and
1502
 
                # that would remove duplication.
1503
 
                parent_trees.extend([
1504
 
                    (parent, self.branch.repository.revision_tree(parent)) for
1505
 
                     parent in merges])
1506
 
                self.set_parent_trees(parent_trees)
1507
 
            if old_tip and old_tip != self.last_revision():
1508
 
                # our last revision was not the prior branch last revision
1509
 
                # and we have converted that last revision to a pending merge.
1510
 
                # base is somewhere between the branch tip now
1511
 
                # and the now pending merge
1512
 
                from bzrlib.revision import common_ancestor
1513
 
                try:
1514
 
                    base_rev_id = common_ancestor(self.branch.last_revision(),
1515
 
                                                  old_tip,
1516
 
                                                  self.branch.repository)
1517
 
                except errors.NoCommonAncestor:
1518
 
                    base_rev_id = None
1519
 
                base_tree = self.branch.repository.revision_tree(base_rev_id)
1520
 
                other_tree = self.branch.repository.revision_tree(old_tip)
1521
 
                result += merge_inner(self.branch,
1522
 
                                      other_tree,
1523
 
                                      base_tree,
1524
 
                                      this_tree=self)
1525
 
            return result
1526
 
        finally:
1527
 
            self.branch.unlock()
 
1504
        # here if old_tip is not None, it is the old tip of the branch before
 
1505
        # it was updated from the master branch. This should become a pending
 
1506
        # merge in the working tree to preserve the user existing work.  we
 
1507
        # cant set that until we update the working trees last revision to be
 
1508
        # one from the new branch, because it will just get absorbed by the
 
1509
        # parent de-duplication logic.
 
1510
        # 
 
1511
        # We MUST save it even if an error occurs, because otherwise the users
 
1512
        # local work is unreferenced and will appear to have been lost.
 
1513
        # 
 
1514
        result = 0
 
1515
        if self.last_revision() != self.branch.last_revision():
 
1516
            # merge tree state up to new branch tip.
 
1517
            basis = self.basis_tree()
 
1518
            to_tree = self.branch.basis_tree()
 
1519
            result += merge_inner(self.branch,
 
1520
                                  to_tree,
 
1521
                                  basis,
 
1522
                                  this_tree=self)
 
1523
            # TODO - dedup parents list with things merged by pull ?
 
1524
            # reuse the tree we've updated to to set the basis:
 
1525
            parent_trees = [(self.branch.last_revision(), to_tree)]
 
1526
            merges = self.get_parent_ids()[1:]
 
1527
            # Ideally we ask the tree for the trees here, that way the working
 
1528
            # tree can decide whether to give us teh entire tree or give us a
 
1529
            # lazy initialised tree. dirstate for instance will have the trees
 
1530
            # in ram already, whereas a last-revision + basis-inventory tree
 
1531
            # will not, but also does not need them when setting parents.
 
1532
            for parent in merges:
 
1533
                parent_trees.append(
 
1534
                    (parent, self.branch.repository.revision_tree(parent)))
 
1535
            if old_tip is not None:
 
1536
                parent_trees.append(
 
1537
                    (old_tip, self.branch.repository.revision_tree(old_tip)))
 
1538
            self.set_parent_trees(parent_trees)
 
1539
        else:
 
1540
            # the working tree had the same last-revision as the master
 
1541
            # branch did. We may still have pivot local work from the local
 
1542
            # branch into old_tip:
 
1543
            if old_tip is not None:
 
1544
                self.add_parent_tree_id(old_tip)
 
1545
        if old_tip and old_tip != self.last_revision():
 
1546
            # our last revision was not the prior branch last revision
 
1547
            # and we have converted that last revision to a pending merge.
 
1548
            # base is somewhere between the branch tip now
 
1549
            # and the now pending merge
 
1550
            from bzrlib.revision import common_ancestor
 
1551
            try:
 
1552
                base_rev_id = common_ancestor(self.branch.last_revision(),
 
1553
                                              old_tip,
 
1554
                                              self.branch.repository)
 
1555
            except errors.NoCommonAncestor:
 
1556
                base_rev_id = None
 
1557
            base_tree = self.branch.repository.revision_tree(base_rev_id)
 
1558
            other_tree = self.branch.repository.revision_tree(old_tip)
 
1559
            result += merge_inner(self.branch,
 
1560
                                  other_tree,
 
1561
                                  base_tree,
 
1562
                                  this_tree=self)
 
1563
        return result
1528
1564
 
1529
1565
    @needs_write_lock
1530
1566
    def _write_inventory(self, inv):