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

  • Committer: Parth Malwankar
  • Date: 2010-02-15 10:46:49 UTC
  • mto: This revision was merged to the branch mainline in revision 5048.
  • Revision ID: parth.malwankar@gmail.com-20100215104649-bo4z8rhqvfibnxhj
updated existing upgrade tests to work.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
# point down
19
19
 
20
20
import os
 
21
import re
21
22
 
22
23
from bzrlib.lazy_import import lazy_import
23
24
lazy_import(globals(), """
25
26
 
26
27
from bzrlib import (
27
28
    builtins,
28
 
    cleanup,
29
29
    commands,
30
30
    errors,
31
31
    osutils,
45
45
 
46
46
 
47
47
class cmd_conflicts(commands.Command):
48
 
    __doc__ = """List files with conflicts.
 
48
    """List files with conflicts.
49
49
 
50
50
    Merge will do its best to combine the changes in two branches, but there
51
51
    are some kinds of problems only a human can fix.  When it encounters those,
59
59
    Use bzr resolve when you have fixed a problem.
60
60
    """
61
61
    takes_options = [
62
 
            'directory',
63
62
            option.Option('text',
64
63
                          help='List paths of files with text conflicts.'),
65
64
        ]
66
65
    _see_also = ['resolve', 'conflict-types']
67
66
 
68
 
    def run(self, text=False, directory=u'.'):
69
 
        wt = workingtree.WorkingTree.open_containing(directory)[0]
 
67
    def run(self, text=False):
 
68
        wt = workingtree.WorkingTree.open_containing(u'.')[0]
70
69
        for conflict in wt.conflicts():
71
70
            if text:
72
71
                if conflict.typestring != 'text conflict':
99
98
 
100
99
 
101
100
class cmd_resolve(commands.Command):
102
 
    __doc__ = """Mark a conflict as resolved.
 
101
    """Mark a conflict as resolved.
103
102
 
104
103
    Merge will do its best to combine the changes in two branches, but there
105
104
    are some kinds of problems only a human can fix.  When it encounters those,
113
112
    aliases = ['resolved']
114
113
    takes_args = ['file*']
115
114
    takes_options = [
116
 
            'directory',
117
115
            option.Option('all', help='Resolve all conflicts in this tree.'),
118
116
            ResolveActionOption(),
119
117
            ]
120
118
    _see_also = ['conflicts']
121
 
    def run(self, file_list=None, all=False, action=None, directory=u'.'):
 
119
    def run(self, file_list=None, all=False, action=None):
122
120
        if all:
123
121
            if file_list:
124
122
                raise errors.BzrCommandError("If --all is specified,"
125
123
                                             " no FILE may be provided")
126
 
            tree = workingtree.WorkingTree.open_containing(directory)[0]
 
124
            tree = workingtree.WorkingTree.open_containing('.')[0]
127
125
            if action is None:
128
126
                action = 'done'
129
127
        else:
437
435
    def action_take_other(self, tree):
438
436
        raise NotImplementedError(self.action_take_other)
439
437
 
440
 
    def _resolve_with_cleanups(self, tree, *args, **kwargs):
441
 
        tt = transform.TreeTransform(tree)
442
 
        op = cleanup.OperationWithCleanups(self._resolve)
443
 
        op.add_cleanup(tt.finalize)
444
 
        op.run_simple(tt, *args, **kwargs)
445
 
 
446
438
 
447
439
class PathConflict(Conflict):
448
440
    """A conflict was encountered merging file paths"""
467
459
        # No additional files have been generated here
468
460
        return []
469
461
 
470
 
    def _resolve(self, tt, file_id, path, winner):
471
 
        """Resolve the conflict.
472
 
 
473
 
        :param tt: The TreeTransform where the conflict is resolved.
474
 
        :param file_id: The retained file id.
475
 
        :param path: The retained path.
476
 
        :param winner: 'this' or 'other' indicates which side is the winner.
477
 
        """
478
 
        path_to_create = None
479
 
        if winner == 'this':
480
 
            if self.path == '<deleted>':
481
 
                return # Nothing to do
482
 
            if self.conflict_path == '<deleted>':
483
 
                path_to_create = self.path
484
 
                revid = tt._tree.get_parent_ids()[0]
485
 
        elif winner == 'other':
486
 
            if self.conflict_path == '<deleted>':
487
 
                return  # Nothing to do
488
 
            if self.path == '<deleted>':
489
 
                path_to_create = self.conflict_path
490
 
                # FIXME: If there are more than two parents we may need to
491
 
                # iterate. Taking the last parent is the safer bet in the mean
492
 
                # time. -- vila 20100309
493
 
                revid = tt._tree.get_parent_ids()[-1]
494
 
        else:
495
 
            # Programmer error
496
 
            raise AssertionError('bad winner: %r' % (winner,))
497
 
        if path_to_create is not None:
498
 
            tid = tt.trans_id_tree_path(path_to_create)
499
 
            transform.create_from_tree(
500
 
                tt, tt.trans_id_tree_path(path_to_create),
501
 
                self._revision_tree(tt._tree, revid), file_id)
502
 
            tt.version_file(file_id, tid)
503
 
 
504
 
        # Adjust the path for the retained file id
505
 
        tid = tt.trans_id_file_id(file_id)
506
 
        parent_tid = tt.get_tree_parent(tid)
507
 
        tt.adjust_path(path, parent_tid, tid)
508
 
        tt.apply()
509
 
 
510
 
    def _revision_tree(self, tree, revid):
511
 
        return tree.branch.repository.revision_tree(revid)
512
 
 
513
 
    def _infer_file_id(self, tree):
514
 
        # Prior to bug #531967, file_id wasn't always set, there may still be
515
 
        # conflict files in the wild so we need to cope with them
516
 
        # Establish which path we should use to find back the file-id
517
 
        possible_paths = []
518
 
        for p in (self.path, self.conflict_path):
519
 
            if p == '<deleted>':
520
 
                # special hard-coded path 
521
 
                continue
522
 
            if p is not None:
523
 
                possible_paths.append(p)
524
 
        # Search the file-id in the parents with any path available
525
 
        file_id = None
526
 
        for revid in tree.get_parent_ids():
527
 
            revtree = self._revision_tree(tree, revid)
528
 
            for p in possible_paths:
529
 
                file_id = revtree.path2id(p)
530
 
                if file_id is not None:
531
 
                    return revtree, file_id
532
 
        return None, None
533
 
 
534
462
    def action_take_this(self, tree):
535
 
        if self.file_id is not None:
536
 
            self._resolve_with_cleanups(tree, self.file_id, self.path,
537
 
                                        winner='this')
538
 
        else:
539
 
            # Prior to bug #531967 we need to find back the file_id and restore
540
 
            # the content from there
541
 
            revtree, file_id = self._infer_file_id(tree)
542
 
            tree.revert([revtree.id2path(file_id)],
543
 
                        old_tree=revtree, backups=False)
 
463
        tree.rename_one(self.conflict_path, self.path)
544
464
 
545
465
    def action_take_other(self, tree):
546
 
        if self.file_id is not None:
547
 
            self._resolve_with_cleanups(tree, self.file_id,
548
 
                                        self.conflict_path,
549
 
                                        winner='other')
550
 
        else:
551
 
            # Prior to bug #531967 we need to find back the file_id and restore
552
 
            # the content from there
553
 
            revtree, file_id = self._infer_file_id(tree)
554
 
            tree.revert([revtree.id2path(file_id)],
555
 
                        old_tree=revtree, backups=False)
 
466
        # just acccept bzr proposal
 
467
        pass
556
468
 
557
469
 
558
470
class ContentsConflict(PathConflict):
559
 
    """The files are of different types (or both binary), or not present"""
 
471
    """The files are of different types, or not present"""
560
472
 
561
473
    has_files = True
562
474
 
567
479
    def associated_filenames(self):
568
480
        return [self.path + suffix for suffix in ('.BASE', '.OTHER')]
569
481
 
570
 
    def _resolve(self, tt, suffix_to_remove):
571
 
        """Resolve the conflict.
572
 
 
573
 
        :param tt: The TreeTransform where the conflict is resolved.
574
 
        :param suffix_to_remove: Either 'THIS' or 'OTHER'
575
 
 
576
 
        The resolution is symmetric, when taking THIS, OTHER is deleted and
577
 
        item.THIS is renamed into item and vice-versa.
578
 
        """
579
 
        try:
580
 
            # Delete 'item.THIS' or 'item.OTHER' depending on
581
 
            # suffix_to_remove
582
 
            tt.delete_contents(
583
 
                tt.trans_id_tree_path(self.path + '.' + suffix_to_remove))
584
 
        except errors.NoSuchFile:
585
 
            # There are valid cases where 'item.suffix_to_remove' either
586
 
            # never existed or was already deleted (including the case
587
 
            # where the user deleted it)
588
 
            pass
589
 
        # Rename 'item.suffix_to_remove' (note that if
590
 
        # 'item.suffix_to_remove' has been deleted, this is a no-op)
591
 
        this_tid = tt.trans_id_file_id(self.file_id)
592
 
        parent_tid = tt.get_tree_parent(this_tid)
593
 
        tt.adjust_path(self.path, parent_tid, this_tid)
594
 
        tt.apply()
595
 
 
 
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
596
486
    def action_take_this(self, tree):
597
 
        self._resolve_with_cleanups(tree, 'OTHER')
 
487
        tree.remove([self.path + '.OTHER'], force=True, keep_files=False)
598
488
 
599
489
    def action_take_other(self, tree):
600
 
        self._resolve_with_cleanups(tree, 'THIS')
 
490
        tree.remove([self.path], force=True, keep_files=False)
 
491
 
601
492
 
602
493
 
603
494
# FIXME: TextConflict is about a single file-id, there never is a conflict_path
708
599
 
709
600
    typestring = 'parent loop'
710
601
 
711
 
    format = 'Conflict moving %(path)s into %(conflict_path)s. %(action)s.'
 
602
    format = 'Conflict moving %(conflict_path)s into %(path)s.  %(action)s.'
712
603
 
713
604
    def action_take_this(self, tree):
714
605
        # just acccept bzr proposal