/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: Robert Collins
  • Date: 2007-04-19 05:21:37 UTC
  • mto: (2425.1.2 integration)
  • mto: This revision was merged to the branch mainline in revision 2427.
  • Revision ID: robertc@robertcollins.net-20070419052137-vsncwlmi8epl5eel
Update existing builtin commands help text to use _see_also. (Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 by Aaron Bentley
2
 
 
 
1
# Copyright (C) 2005 Aaron Bentley, Canonical Ltd
 
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
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
20
# point down
21
21
 
22
22
import os
 
23
 
 
24
from bzrlib.lazy_import import lazy_import
 
25
lazy_import(globals(), """
23
26
import errno
24
27
 
25
 
import bzrlib
26
 
from bzrlib.commands import register_command
27
 
from bzrlib.errors import BzrCommandError, NotConflicted, UnsupportedOperation
 
28
from bzrlib import (
 
29
    builtins,
 
30
    commands,
 
31
    errors,
 
32
    osutils,
 
33
    rio,
 
34
    trace,
 
35
    )
 
36
""")
28
37
from bzrlib.option import Option
29
 
from bzrlib.osutils import rename, delete_any
30
 
from bzrlib.rio import Stanza
31
38
 
32
39
 
33
40
CONFLICT_SUFFIXES = ('.THIS', '.BASE', '.OTHER')
34
41
 
35
42
 
36
 
class cmd_conflicts(bzrlib.commands.Command):
 
43
class cmd_conflicts(commands.Command):
37
44
    """List files with conflicts.
38
45
 
39
46
    Merge will do its best to combine the changes in two branches, but there
41
48
    it will mark a conflict.  A conflict means that you need to fix something,
42
49
    before you should commit.
43
50
 
 
51
    Conflicts normally are listed as short, human-readable messages.  If --text
 
52
    is supplied, the pathnames of files with text conflicts are listed,
 
53
    instead.  (This is useful for editing all files with text conflicts.)
 
54
 
44
55
    Use bzr resolve when you have fixed a problem.
45
56
 
46
 
    (conflicts are determined by the presence of .BASE .TREE, and .OTHER 
47
 
    files.)
48
 
 
49
57
    See also bzr resolve.
50
58
    """
51
 
    def run(self):
 
59
    takes_options = [Option('text', help='list text conflicts by pathname')]
 
60
 
 
61
    def run(self, text=False):
52
62
        from bzrlib.workingtree import WorkingTree
53
63
        wt = WorkingTree.open_containing(u'.')[0]
54
64
        for conflict in wt.conflicts():
55
 
            print conflict
56
 
 
57
 
 
58
 
class cmd_resolve(bzrlib.commands.Command):
 
65
            if text:
 
66
                if conflict.typestring != 'text conflict':
 
67
                    continue
 
68
                self.outf.write(conflict.path + '\n')
 
69
            else:
 
70
                self.outf.write(str(conflict) + '\n')
 
71
 
 
72
 
 
73
class cmd_resolve(commands.Command):
59
74
    """Mark a conflict as resolved.
60
75
 
61
76
    Merge will do its best to combine the changes in two branches, but there
63
78
    it will mark a conflict.  A conflict means that you need to fix something,
64
79
    before you should commit.
65
80
 
66
 
    Once you have fixed a problem, use "bzr resolve FILE.." to mark
67
 
    individual files as fixed, or "bzr resolve --all" to mark all conflicts as
68
 
    resolved.
 
81
    Once you have fixed a problem, use "bzr resolve" to automatically mark
 
82
    text conflicts as fixed, resolve FILE to mark a specific conflict as
 
83
    resolved, or "bzr resolve --all" to mark all conflicts as resolved.
69
84
 
70
85
    See also bzr conflicts.
71
86
    """
76
91
        from bzrlib.workingtree import WorkingTree
77
92
        if all:
78
93
            if file_list:
79
 
                raise BzrCommandError("If --all is specified, no FILE may be provided")
 
94
                raise errors.BzrCommandError("If --all is specified,"
 
95
                                             " no FILE may be provided")
80
96
            tree = WorkingTree.open_containing('.')[0]
81
97
            resolve(tree)
82
98
        else:
 
99
            tree, file_list = builtins.tree_files(file_list)
83
100
            if file_list is None:
84
 
                raise BzrCommandError("command 'resolve' needs one or more FILE, or --all")
85
 
            tree = WorkingTree.open_containing(file_list[0])[0]
86
 
            to_resolve = [tree.relpath(p) for p in file_list]
87
 
            resolve(tree, to_resolve)
 
101
                un_resolved, resolved = tree.auto_resolve()
 
102
                if len(un_resolved) > 0:
 
103
                    trace.note('%d conflict(s) auto-resolved.', len(resolved))
 
104
                    trace.note('Remaining conflicts:')
 
105
                    for conflict in un_resolved:
 
106
                        trace.note(conflict)
 
107
                    return 1
 
108
                else:
 
109
                    trace.note('All conflicts resolved.')
 
110
                    return 0
 
111
            else:
 
112
                resolve(tree, file_list)
88
113
 
89
114
 
90
115
def resolve(tree, paths=None, ignore_misses=False):
91
 
    tree.lock_write()
 
116
    tree.lock_tree_write()
92
117
    try:
93
118
        tree_conflicts = tree.conflicts()
94
119
        if paths is None:
99
124
                tree_conflicts.select_conflicts(tree, paths, ignore_misses)
100
125
        try:
101
126
            tree.set_conflicts(new_conflicts)
102
 
        except UnsupportedOperation:
 
127
        except errors.UnsupportedOperation:
103
128
            pass
104
129
        selected_conflicts.remove_files(tree)
105
130
    finally:
113
138
    """
114
139
    conflicted = False
115
140
    try:
116
 
        rename(filename + ".THIS", filename)
 
141
        osutils.rename(filename + ".THIS", filename)
117
142
        conflicted = True
118
143
    except OSError, e:
119
144
        if e.errno != errno.ENOENT:
131
156
        if e.errno != errno.ENOENT:
132
157
            raise
133
158
    if not conflicted:
134
 
        raise NotConflicted(filename)
 
159
        raise errors.NotConflicted(filename)
135
160
 
136
161
 
137
162
class ConflictList(object):
198
223
                continue
199
224
            for suffix in CONFLICT_SUFFIXES:
200
225
                try:
201
 
                    delete_any(tree.abspath(conflict.path+suffix))
 
226
                    osutils.delete_any(tree.abspath(conflict.path+suffix))
202
227
                except OSError, e:
203
228
                    if e.errno != errno.ENOENT:
204
229
                        raise
207
232
        """Select the conflicts associated with paths in a tree.
208
233
        
209
234
        File-ids are also used for this.
 
235
        :return: a pair of ConflictLists: (not_selected, selected)
210
236
        """
211
237
        path_set = set(paths)
212
238
        ids = {}
257
283
 
258
284
    def __init__(self, path, file_id=None):
259
285
        self.path = path
260
 
        self.file_id = file_id
 
286
        # warn turned off, because the factory blindly transfers the Stanza
 
287
        # values to __init__ and Stanza is purely a Unicode api.
 
288
        self.file_id = osutils.safe_file_id(file_id, warn=False)
261
289
 
262
290
    def as_stanza(self):
263
 
        s = Stanza(type=self.typestring, path=self.path)
 
291
        s = rio.Stanza(type=self.typestring, path=self.path)
264
292
        if self.file_id is not None:
265
 
            s.add('file_id', self.file_id)
 
293
            # Stanza requires Unicode apis
 
294
            s.add('file_id', self.file_id.decode('utf8'))
266
295
        return s
267
296
 
268
297
    def _cmp_list(self):
273
302
            return -1
274
303
        return cmp(self._cmp_list(), other._cmp_list())
275
304
 
 
305
    def __hash__(self):
 
306
        return hash((type(self), self.path, self.file_id))
 
307
 
276
308
    def __eq__(self, other):
277
309
        return self.__cmp__(other) == 0
278
310
 
292
324
        global ctype
293
325
        return ctype[type](**kwargs)
294
326
 
 
327
    @staticmethod
 
328
    def sort_key(conflict):
 
329
        if conflict.path is not None:
 
330
            return conflict.path, conflict.typestring
 
331
        elif getattr(conflict, "conflict_path", None) is not None:
 
332
            return conflict.conflict_path, conflict.typestring
 
333
        else:
 
334
            return None, conflict.typestring
 
335
 
295
336
 
296
337
class PathConflict(Conflict):
297
338
    """A conflict was encountered merging file paths"""
364
405
                 conflict_file_id=None):
365
406
        HandledConflict.__init__(self, action, path, file_id)
366
407
        self.conflict_path = conflict_path 
367
 
        self.conflict_file_id = conflict_file_id
 
408
        # warn turned off, because the factory blindly transfers the Stanza
 
409
        # values to __init__.
 
410
        self.conflict_file_id = osutils.safe_file_id(conflict_file_id,
 
411
                                                     warn=False)
368
412
        
369
413
    def _cmp_list(self):
370
414
        return HandledConflict._cmp_list(self) + [self.conflict_path, 
374
418
        s = HandledConflict.as_stanza(self)
375
419
        s.add('conflict_path', self.conflict_path)
376
420
        if self.conflict_file_id is not None:
377
 
            s.add('conflict_file_id', self.conflict_file_id)
 
421
            s.add('conflict_file_id', self.conflict_file_id.decode('utf8'))
378
422
            
379
423
        return s
380
424
 
419
463
 
420
464
    typestring = 'unversioned parent'
421
465
 
422
 
    format = 'Conflict adding versioned files to %(path)s.  %(action)s.'
 
466
    format = 'Conflict because %(path)s is not versioned, but has versioned'\
 
467
             ' children.  %(action)s.'
423
468
 
424
469
 
425
470
class MissingParent(HandledConflict):
426
471
    """An attempt to add files to a directory that is not present.
427
 
    Typically, the result of a merge where one tree deleted the directory and
428
 
    the other added a file to it.
 
472
    Typically, the result of a merge where THIS deleted the directory and
 
473
    the OTHER added a file to it.
 
474
    See also: DeletingParent (same situation, reversed THIS and OTHER)
429
475
    """
430
476
 
431
477
    typestring = 'missing parent'
433
479
    format = 'Conflict adding files to %(path)s.  %(action)s.'
434
480
 
435
481
 
 
482
class DeletingParent(HandledConflict):
 
483
    """An attempt to add files to a directory that is not present.
 
484
    Typically, the result of a merge where one OTHER deleted the directory and
 
485
    the THIS added a file to it.
 
486
    """
 
487
 
 
488
    typestring = 'deleting parent'
 
489
 
 
490
    format = "Conflict: can't delete %(path)s because it is not empty.  "\
 
491
             "%(action)s."
 
492
 
436
493
 
437
494
ctype = {}
438
495
 
445
502
 
446
503
 
447
504
register_types(ContentsConflict, TextConflict, PathConflict, DuplicateID,
448
 
               DuplicateEntry, ParentLoop, UnversionedParent, MissingParent,)
 
505
               DuplicateEntry, ParentLoop, UnversionedParent, MissingParent,
 
506
               DeletingParent,)