~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/conflicts.py

  • Committer: Ian Clatworthy
  • Date: 2010-03-30 20:13:52 UTC
  • mto: This revision was merged to the branch mainline in revision 5125.
  • Revision ID: ian.clatworthy@canonical.com-20100330201352-vw2gtujybyg3rvwc
whitespace fix in win32 installer

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
 
27
27
from bzrlib import (
28
28
    builtins,
 
29
    cleanup,
29
30
    commands,
30
31
    errors,
31
32
    osutils,
435
436
    def action_take_other(self, tree):
436
437
        raise NotImplementedError(self.action_take_other)
437
438
 
 
439
    def _resolve_with_cleanups(self, tree, *args, **kwargs):
 
440
        tt = transform.TreeTransform(tree)
 
441
        op = cleanup.OperationWithCleanups(self._resolve)
 
442
        op.add_cleanup(tt.finalize)
 
443
        op.run_simple(tt, *args, **kwargs)
 
444
 
438
445
 
439
446
class PathConflict(Conflict):
440
447
    """A conflict was encountered merging file paths"""
459
466
        # No additional files have been generated here
460
467
        return []
461
468
 
 
469
    def _resolve(self, tt, file_id, path, winner):
 
470
        """Resolve the conflict.
 
471
 
 
472
        :param tt: The TreeTransform where the conflict is resolved.
 
473
        :param file_id: The retained file id.
 
474
        :param path: The retained path.
 
475
        :param winner: 'this' or 'other' indicates which side is the winner.
 
476
        """
 
477
        path_to_create = None
 
478
        if winner == 'this':
 
479
            if self.path == '<deleted>':
 
480
                return # Nothing to do
 
481
            if self.conflict_path == '<deleted>':
 
482
                path_to_create = self.path
 
483
                revid = tt._tree.get_parent_ids()[0]
 
484
        elif winner == 'other':
 
485
            if self.conflict_path == '<deleted>':
 
486
                return  # Nothing to do
 
487
            if self.path == '<deleted>':
 
488
                path_to_create = self.conflict_path
 
489
                # FIXME: If there are more than two parents we may need to
 
490
                # iterate. Taking the last parent is the safer bet in the mean
 
491
                # time. -- vila 20100309
 
492
                revid = tt._tree.get_parent_ids()[-1]
 
493
        else:
 
494
            # Programmer error
 
495
            raise AssertionError('bad winner: %r' % (winner,))
 
496
        if path_to_create is not None:
 
497
            tid = tt.trans_id_tree_path(path_to_create)
 
498
            transform.create_from_tree(
 
499
                tt, tt.trans_id_tree_path(path_to_create),
 
500
                self._revision_tree(tt._tree, revid), file_id)
 
501
            tt.version_file(file_id, tid)
 
502
 
 
503
        # Adjust the path for the retained file id
 
504
        tid = tt.trans_id_file_id(file_id)
 
505
        parent_tid = tt.get_tree_parent(tid)
 
506
        tt.adjust_path(path, parent_tid, tid)
 
507
        tt.apply()
 
508
 
 
509
    def _revision_tree(self, tree, revid):
 
510
        return tree.branch.repository.revision_tree(revid)
 
511
 
 
512
    def _infer_file_id(self, tree):
 
513
        # Prior to bug #531967, file_id wasn't always set, there may still be
 
514
        # conflict files in the wild so we need to cope with them
 
515
        # Establish which path we should use to find back the file-id
 
516
        possible_paths = []
 
517
        for p in (self.path, self.conflict_path):
 
518
            if p == '<deleted>':
 
519
                # special hard-coded path 
 
520
                continue
 
521
            if p is not None:
 
522
                possible_paths.append(p)
 
523
        # Search the file-id in the parents with any path available
 
524
        file_id = None
 
525
        for revid in tree.get_parent_ids():
 
526
            revtree = self._revision_tree(tree, revid)
 
527
            for p in possible_paths:
 
528
                file_id = revtree.path2id(p)
 
529
                if file_id is not None:
 
530
                    return revtree, file_id
 
531
        return None, None
 
532
 
462
533
    def action_take_this(self, tree):
463
 
        tree.rename_one(self.conflict_path, self.path)
 
534
        if self.file_id is not None:
 
535
            self._resolve_with_cleanups(tree, self.file_id, self.path,
 
536
                                        winner='this')
 
537
        else:
 
538
            # Prior to bug #531967 we need to find back the file_id and restore
 
539
            # the content from there
 
540
            revtree, file_id = self._infer_file_id(tree)
 
541
            tree.revert([revtree.id2path(file_id)],
 
542
                        old_tree=revtree, backups=False)
464
543
 
465
544
    def action_take_other(self, tree):
466
 
        # just acccept bzr proposal
467
 
        pass
 
545
        if self.file_id is not None:
 
546
            self._resolve_with_cleanups(tree, self.file_id,
 
547
                                        self.conflict_path,
 
548
                                        winner='other')
 
549
        else:
 
550
            # Prior to bug #531967 we need to find back the file_id and restore
 
551
            # the content from there
 
552
            revtree, file_id = self._infer_file_id(tree)
 
553
            tree.revert([revtree.id2path(file_id)],
 
554
                        old_tree=revtree, backups=False)
468
555
 
469
556
 
470
557
class ContentsConflict(PathConflict):
471
 
    """The files are of different types, or not present"""
 
558
    """The files are of different types (or both binary), or not present"""
472
559
 
473
560
    has_files = True
474
561
 
479
566
    def associated_filenames(self):
480
567
        return [self.path + suffix for suffix in ('.BASE', '.OTHER')]
481
568
 
482
 
    # FIXME: I smell something weird here and it seems we should be able to be
483
 
    # more coherent with some other conflict ? bzr *did* a choice there but
484
 
    # neither action_take_this nor action_take_other reflect that...
485
 
    # -- vila 20091224
 
569
    def _resolve(self, tt, suffix_to_remove):
 
570
        """Resolve the conflict.
 
571
 
 
572
        :param tt: The TreeTransform where the conflict is resolved.
 
573
        :param suffix_to_remove: Either 'THIS' or 'OTHER'
 
574
 
 
575
        The resolution is symmetric, when taking THIS, OTHER is deleted and
 
576
        item.THIS is renamed into item and vice-versa.
 
577
        """
 
578
        try:
 
579
            # Delete 'item.THIS' or 'item.OTHER' depending on
 
580
            # suffix_to_remove
 
581
            tt.delete_contents(
 
582
                tt.trans_id_tree_path(self.path + '.' + suffix_to_remove))
 
583
        except errors.NoSuchFile:
 
584
            # There are valid cases where 'item.suffix_to_remove' either
 
585
            # never existed or was already deleted (including the case
 
586
            # where the user deleted it)
 
587
            pass
 
588
        # Rename 'item.suffix_to_remove' (note that if
 
589
        # 'item.suffix_to_remove' has been deleted, this is a no-op)
 
590
        this_tid = tt.trans_id_file_id(self.file_id)
 
591
        parent_tid = tt.get_tree_parent(this_tid)
 
592
        tt.adjust_path(self.path, parent_tid, this_tid)
 
593
        tt.apply()
 
594
 
486
595
    def action_take_this(self, tree):
487
 
        tree.remove([self.path + '.OTHER'], force=True, keep_files=False)
 
596
        self._resolve_with_cleanups(tree, 'OTHER')
488
597
 
489
598
    def action_take_other(self, tree):
490
 
        tree.remove([self.path], force=True, keep_files=False)
491
 
 
 
599
        self._resolve_with_cleanups(tree, 'THIS')
492
600
 
493
601
 
494
602
# FIXME: TextConflict is about a single file-id, there never is a conflict_path
599
707
 
600
708
    typestring = 'parent loop'
601
709
 
602
 
    format = 'Conflict moving %(conflict_path)s into %(path)s.  %(action)s.'
 
710
    format = 'Conflict moving %(path)s into %(conflict_path)s. %(action)s.'
603
711
 
604
712
    def action_take_this(self, tree):
605
713
        # just acccept bzr proposal