~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/conflicts.py

  • Committer: Jelmer Vernooij
  • Date: 2009-01-28 18:42:55 UTC
  • mto: This revision was merged to the branch mainline in revision 3968.
  • Revision ID: jelmer@samba.org-20090128184255-bdmklkvm83ltk191
Update NEWS

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Aaron Bentley, Canonical Ltd
 
1
# Copyright (C) 2005, 2007 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
26
26
import errno
27
27
 
28
28
from bzrlib import (
 
29
    builtins,
29
30
    commands,
30
31
    errors,
31
32
    osutils,
32
33
    rio,
 
34
    trace,
33
35
    )
34
36
""")
35
37
from bzrlib.option import Option
54
56
 
55
57
    See also bzr resolve.
56
58
    """
57
 
    takes_options = [Option('text', help='list text conflicts by pathname')]
 
59
    takes_options = [
 
60
            Option('text',
 
61
                   help='List paths of files with text conflicts.'),
 
62
        ]
58
63
 
59
64
    def run(self, text=False):
60
65
        from bzrlib.workingtree import WorkingTree
76
81
    it will mark a conflict.  A conflict means that you need to fix something,
77
82
    before you should commit.
78
83
 
79
 
    Once you have fixed a problem, use "bzr resolve FILE.." to mark
80
 
    individual files as fixed, or "bzr resolve --all" to mark all conflicts as
81
 
    resolved.
 
84
    Once you have fixed a problem, use "bzr resolve" to automatically mark
 
85
    text conflicts as fixed, resolve FILE to mark a specific conflict as
 
86
    resolved, or "bzr resolve --all" to mark all conflicts as resolved.
82
87
 
83
88
    See also bzr conflicts.
84
89
    """
85
90
    aliases = ['resolved']
86
91
    takes_args = ['file*']
87
 
    takes_options = [Option('all', help='Resolve all conflicts in this tree')]
 
92
    takes_options = [
 
93
            Option('all', help='Resolve all conflicts in this tree.'),
 
94
            ]
88
95
    def run(self, file_list=None, all=False):
89
96
        from bzrlib.workingtree import WorkingTree
90
97
        if all:
94
101
            tree = WorkingTree.open_containing('.')[0]
95
102
            resolve(tree)
96
103
        else:
 
104
            tree, file_list = builtins.tree_files(file_list)
97
105
            if file_list is None:
98
 
                raise errors.BzrCommandError("command 'resolve' needs one or"
99
 
                                             " more FILE, or --all")
100
 
            tree = WorkingTree.open_containing(file_list[0])[0]
101
 
            to_resolve = [tree.relpath(p) for p in file_list]
102
 
            resolve(tree, to_resolve)
103
 
 
104
 
 
105
 
def resolve(tree, paths=None, ignore_misses=False):
 
106
                un_resolved, resolved = tree.auto_resolve()
 
107
                if len(un_resolved) > 0:
 
108
                    trace.note('%d conflict(s) auto-resolved.', len(resolved))
 
109
                    trace.note('Remaining conflicts:')
 
110
                    for conflict in un_resolved:
 
111
                        trace.note(conflict)
 
112
                    return 1
 
113
                else:
 
114
                    trace.note('All conflicts resolved.')
 
115
                    return 0
 
116
            else:
 
117
                resolve(tree, file_list)
 
118
 
 
119
 
 
120
def resolve(tree, paths=None, ignore_misses=False, recursive=False):
 
121
    """Resolve some or all of the conflicts in a working tree.
 
122
 
 
123
    :param paths: If None, resolve all conflicts.  Otherwise, select only
 
124
        specified conflicts.
 
125
    :param recursive: If True, then elements of paths which are directories
 
126
        have all their children resolved, etc.  When invoked as part of
 
127
        recursive commands like revert, this should be True.  For commands
 
128
        or applications wishing finer-grained control, like the resolve
 
129
        command, this should be False.
 
130
    :ignore_misses: If False, warnings will be printed if the supplied paths
 
131
        do not have conflicts.
 
132
    """
106
133
    tree.lock_tree_write()
107
134
    try:
108
135
        tree_conflicts = tree.conflicts()
111
138
            selected_conflicts = tree_conflicts
112
139
        else:
113
140
            new_conflicts, selected_conflicts = \
114
 
                tree_conflicts.select_conflicts(tree, paths, ignore_misses)
 
141
                tree_conflicts.select_conflicts(tree, paths, ignore_misses,
 
142
                    recursive)
115
143
        try:
116
144
            tree.set_conflicts(new_conflicts)
117
145
        except errors.UnsupportedOperation:
218
246
                    if e.errno != errno.ENOENT:
219
247
                        raise
220
248
 
221
 
    def select_conflicts(self, tree, paths, ignore_misses=False):
 
249
    def select_conflicts(self, tree, paths, ignore_misses=False,
 
250
                         recurse=False):
222
251
        """Select the conflicts associated with paths in a tree.
223
252
        
224
253
        File-ids are also used for this.
243
272
                if cpath in path_set:
244
273
                    selected = True
245
274
                    selected_paths.add(cpath)
 
275
                if recurse:
 
276
                    if osutils.is_inside_any(path_set, cpath):
 
277
                        selected = True
 
278
                        selected_paths.add(cpath)
 
279
 
246
280
            for key in ('file_id', 'conflict_file_id'):
247
281
                cfile_id = getattr(conflict, key, None)
248
282
                if cfile_id is None:
273
307
 
274
308
    def __init__(self, path, file_id=None):
275
309
        self.path = path
276
 
        self.file_id = file_id
 
310
        # warn turned off, because the factory blindly transfers the Stanza
 
311
        # values to __init__ and Stanza is purely a Unicode api.
 
312
        self.file_id = osutils.safe_file_id(file_id, warn=False)
277
313
 
278
314
    def as_stanza(self):
279
315
        s = rio.Stanza(type=self.typestring, path=self.path)
280
316
        if self.file_id is not None:
281
 
            s.add('file_id', self.file_id)
 
317
            # Stanza requires Unicode apis
 
318
            s.add('file_id', self.file_id.decode('utf8'))
282
319
        return s
283
320
 
284
321
    def _cmp_list(self):
392
429
                 conflict_file_id=None):
393
430
        HandledConflict.__init__(self, action, path, file_id)
394
431
        self.conflict_path = conflict_path 
395
 
        self.conflict_file_id = conflict_file_id
 
432
        # warn turned off, because the factory blindly transfers the Stanza
 
433
        # values to __init__.
 
434
        self.conflict_file_id = osutils.safe_file_id(conflict_file_id,
 
435
                                                     warn=False)
396
436
        
397
437
    def _cmp_list(self):
398
438
        return HandledConflict._cmp_list(self) + [self.conflict_path, 
402
442
        s = HandledConflict.as_stanza(self)
403
443
        s.add('conflict_path', self.conflict_path)
404
444
        if self.conflict_file_id is not None:
405
 
            s.add('conflict_file_id', self.conflict_file_id)
 
445
            s.add('conflict_file_id', self.conflict_file_id.decode('utf8'))
406
446
            
407
447
        return s
408
448
 
475
515
             "%(action)s."
476
516
 
477
517
 
 
518
class NonDirectoryParent(HandledConflict):
 
519
    """An attempt to add files to a directory that is not a director or
 
520
    an attempt to change the kind of a directory with files.
 
521
    """
 
522
 
 
523
    typestring = 'non-directory parent'
 
524
 
 
525
    format = "Conflict: %(path)s is not a directory, but has files in it."\
 
526
             "  %(action)s."
 
527
 
478
528
ctype = {}
479
529
 
480
530
 
487
537
 
488
538
register_types(ContentsConflict, TextConflict, PathConflict, DuplicateID,
489
539
               DuplicateEntry, ParentLoop, UnversionedParent, MissingParent,
490
 
               DeletingParent,)
 
540
               DeletingParent, NonDirectoryParent)