/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2052.3.3 by John Arbash Meinel
Add (c) Canonical to files that Aaron has approved
1
# Copyright (C) 2005 Aaron Bentley, Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1185.14.3 by Aaron Bentley
Copied conflict lister in
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1185.14.3 by Aaron Bentley
Copied conflict lister in
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1185.14.3 by Aaron Bentley
Copied conflict lister in
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
1185.16.11 by Martin Pool
todo
17
# TODO: Move this into builtins
18
19
# TODO: 'bzr resolve' should accept a directory name and work from that 
20
# point down
21
1185.16.33 by Martin Pool
- move 'conflict' and 'resolved' from shipped plugin to regular builtins
22
import os
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
23
24
from bzrlib.lazy_import import lazy_import
25
lazy_import(globals(), """
1185.16.33 by Martin Pool
- move 'conflict' and 'resolved' from shipped plugin to regular builtins
26
import errno
27
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
28
from bzrlib import (
2120.7.3 by Aaron Bentley
Update resolve command to automatically mark conflicts as resolved
29
    builtins,
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
30
    commands,
31
    errors,
32
    osutils,
33
    rio,
2120.7.3 by Aaron Bentley
Update resolve command to automatically mark conflicts as resolved
34
    trace,
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
35
    )
36
""")
1551.2.18 by Aaron Bentley
Updated docs to clarify conflict handling
37
from bzrlib.option import Option
1534.10.6 by Aaron Bentley
Conflict serialization working for WorkingTree3
38
39
40
CONFLICT_SUFFIXES = ('.THIS', '.BASE', '.OTHER')
41
1185.14.3 by Aaron Bentley
Copied conflict lister in
42
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
43
class cmd_conflicts(commands.Command):
1185.14.3 by Aaron Bentley
Copied conflict lister in
44
    """List files with conflicts.
1551.2.18 by Aaron Bentley
Updated docs to clarify conflict handling
45
46
    Merge will do its best to combine the changes in two branches, but there
47
    are some kinds of problems only a human can fix.  When it encounters those,
48
    it will mark a conflict.  A conflict means that you need to fix something,
49
    before you should commit.
50
1551.9.8 by Aaron Bentley
Add --text parameter to conflicts
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
1551.2.18 by Aaron Bentley
Updated docs to clarify conflict handling
55
    Use bzr resolve when you have fixed a problem.
56
57
    See also bzr resolve.
1185.14.3 by Aaron Bentley
Copied conflict lister in
58
    """
2598.1.1 by Martin Pool
Add test for and documentation of option style, fix up existing options to comply
59
    takes_options = [
60
            Option('text',
61
                   help='List paths of files with text conflicts.'),
62
        ]
1551.9.8 by Aaron Bentley
Add --text parameter to conflicts
63
64
    def run(self, text=False):
1534.10.6 by Aaron Bentley
Conflict serialization working for WorkingTree3
65
        from bzrlib.workingtree import WorkingTree
1534.10.9 by Aaron Bentley
Switched display functions to conflict_lines
66
        wt = WorkingTree.open_containing(u'.')[0]
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
67
        for conflict in wt.conflicts():
1551.9.8 by Aaron Bentley
Add --text parameter to conflicts
68
            if text:
69
                if conflict.typestring != 'text conflict':
70
                    continue
71
                self.outf.write(conflict.path + '\n')
72
            else:
73
                self.outf.write(str(conflict) + '\n')
1185.14.3 by Aaron Bentley
Copied conflict lister in
74
1652.1.1 by Martin Pool
Fix 'bzr resolve' run from subdirectory
75
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
76
class cmd_resolve(commands.Command):
1185.14.3 by Aaron Bentley
Copied conflict lister in
77
    """Mark a conflict as resolved.
1551.2.18 by Aaron Bentley
Updated docs to clarify conflict handling
78
79
    Merge will do its best to combine the changes in two branches, but there
80
    are some kinds of problems only a human can fix.  When it encounters those,
81
    it will mark a conflict.  A conflict means that you need to fix something,
82
    before you should commit.
83
2120.7.3 by Aaron Bentley
Update resolve command to automatically mark conflicts as 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.
1551.2.18 by Aaron Bentley
Updated docs to clarify conflict handling
87
88
    See also bzr conflicts.
1185.14.3 by Aaron Bentley
Copied conflict lister in
89
    """
1185.33.24 by Martin Pool
Add alias 'resolved'
90
    aliases = ['resolved']
1185.14.3 by Aaron Bentley
Copied conflict lister in
91
    takes_args = ['file*']
1551.2.18 by Aaron Bentley
Updated docs to clarify conflict handling
92
    takes_options = [Option('all', help='Resolve all conflicts in this tree')]
1185.14.3 by Aaron Bentley
Copied conflict lister in
93
    def run(self, file_list=None, all=False):
1534.10.6 by Aaron Bentley
Conflict serialization working for WorkingTree3
94
        from bzrlib.workingtree import WorkingTree
1652.1.3 by Martin Pool
Improved bzr resolve command line handling
95
        if all:
96
            if file_list:
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
97
                raise errors.BzrCommandError("If --all is specified,"
98
                                             " no FILE may be provided")
1652.1.3 by Martin Pool
Improved bzr resolve command line handling
99
            tree = WorkingTree.open_containing('.')[0]
100
            resolve(tree)
1185.14.3 by Aaron Bentley
Copied conflict lister in
101
        else:
2120.7.3 by Aaron Bentley
Update resolve command to automatically mark conflicts as resolved
102
            tree, file_list = builtins.tree_files(file_list)
1652.1.3 by Martin Pool
Improved bzr resolve command line handling
103
            if file_list is None:
2120.7.3 by Aaron Bentley
Update resolve command to automatically mark conflicts as resolved
104
                un_resolved, resolved = tree.auto_resolve()
105
                if len(un_resolved) > 0:
106
                    trace.note('%d conflict(s) auto-resolved.', len(resolved))
107
                    trace.note('Remaining conflicts:')
108
                    for conflict in un_resolved:
109
                        trace.note(conflict)
110
                    return 1
111
                else:
112
                    trace.note('All conflicts resolved.')
113
                    return 0
114
            else:
2120.7.4 by Aaron Bentley
Fix normal resolve
115
                resolve(tree, file_list)
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
116
117
1534.10.15 by Aaron Bentley
Revert does resolve
118
def resolve(tree, paths=None, ignore_misses=False):
1997.1.3 by Robert Collins
All WorkingTree methods which write to the tree, but not to the branch
119
    tree.lock_tree_write()
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
120
    try:
1534.10.23 by Aaron Bentley
Removed conflicts_to_stanzas and stanzas_to_conflicts
121
        tree_conflicts = tree.conflicts()
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
122
        if paths is None:
1534.10.25 by Aaron Bentley
Move select_conflicts into ConflictList
123
            new_conflicts = ConflictList()
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
124
            selected_conflicts = tree_conflicts
125
        else:
126
            new_conflicts, selected_conflicts = \
1534.10.25 by Aaron Bentley
Move select_conflicts into ConflictList
127
                tree_conflicts.select_conflicts(tree, paths, ignore_misses)
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
128
        try:
1534.10.25 by Aaron Bentley
Move select_conflicts into ConflictList
129
            tree.set_conflicts(new_conflicts)
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
130
        except errors.UnsupportedOperation:
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
131
            pass
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
132
        selected_conflicts.remove_files(tree)
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
133
    finally:
134
        tree.unlock()
135
136
1185.35.1 by Aaron Bentley
Implemented conflicts.restore
137
def restore(filename):
138
    """\
139
    Restore a conflicted file to the state it was in before merging.
140
    Only text restoration supported at present.
141
    """
142
    conflicted = False
143
    try:
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
144
        osutils.rename(filename + ".THIS", filename)
1185.35.1 by Aaron Bentley
Implemented conflicts.restore
145
        conflicted = True
146
    except OSError, e:
147
        if e.errno != errno.ENOENT:
148
            raise
149
    try:
150
        os.unlink(filename + ".BASE")
151
        conflicted = True
152
    except OSError, e:
153
        if e.errno != errno.ENOENT:
154
            raise
155
    try:
156
        os.unlink(filename + ".OTHER")
157
        conflicted = True
158
    except OSError, e:
159
        if e.errno != errno.ENOENT:
160
            raise
161
    if not conflicted:
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
162
        raise errors.NotConflicted(filename)
1534.10.4 by Aaron Bentley
Implemented conflict serialization
163
164
1534.10.22 by Aaron Bentley
Got ConflictList implemented
165
class ConflictList(object):
1652.1.1 by Martin Pool
Fix 'bzr resolve' run from subdirectory
166
    """List of conflicts.
167
168
    Typically obtained from WorkingTree.conflicts()
169
1534.10.22 by Aaron Bentley
Got ConflictList implemented
170
    Can be instantiated from stanzas or from Conflict subclasses.
171
    """
172
173
    def __init__(self, conflicts=None):
174
        object.__init__(self)
175
        if conflicts is None:
176
            self.__list = []
177
        else:
178
            self.__list = conflicts
179
1652.1.1 by Martin Pool
Fix 'bzr resolve' run from subdirectory
180
    def is_empty(self):
181
        return len(self.__list) == 0
182
1534.10.22 by Aaron Bentley
Got ConflictList implemented
183
    def __len__(self):
184
        return len(self.__list)
185
186
    def __iter__(self):
187
        return iter(self.__list)
188
189
    def __getitem__(self, key):
190
        return self.__list[key]
191
192
    def append(self, conflict):
193
        return self.__list.append(conflict)
194
195
    def __eq__(self, other_list):
196
        return list(self) == list(other_list)
197
198
    def __ne__(self, other_list):
199
        return not (self == other_list)
200
201
    def __repr__(self):
202
        return "ConflictList(%r)" % self.__list
203
204
    @staticmethod
205
    def from_stanzas(stanzas):
206
        """Produce a new ConflictList from an iterable of stanzas"""
207
        conflicts = ConflictList()
208
        for stanza in stanzas:
209
            conflicts.append(Conflict.factory(**stanza.as_dict()))
210
        return conflicts
211
212
    def to_stanzas(self):
213
        """Generator of stanzas"""
214
        for conflict in self:
215
            yield conflict.as_stanza()
216
            
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
217
    def to_strings(self):
218
        """Generate strings for the provided conflicts"""
219
        for conflict in self:
220
            yield str(conflict)
221
222
    def remove_files(self, tree):
1534.10.25 by Aaron Bentley
Move select_conflicts into ConflictList
223
        """Remove the THIS, BASE and OTHER files for listed conflicts"""
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
224
        for conflict in self:
225
            if not conflict.has_files:
226
                continue
227
            for suffix in CONFLICT_SUFFIXES:
228
                try:
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
229
                    osutils.delete_any(tree.abspath(conflict.path+suffix))
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
230
                except OSError, e:
231
                    if e.errno != errno.ENOENT:
232
                        raise
1534.10.21 by Aaron Bentley
Moved and renamed conflict functions
233
1534.10.25 by Aaron Bentley
Move select_conflicts into ConflictList
234
    def select_conflicts(self, tree, paths, ignore_misses=False):
235
        """Select the conflicts associated with paths in a tree.
236
        
237
        File-ids are also used for this.
1551.7.10 by Aaron Bentley
Remerge doesn't clear unrelated conflicts
238
        :return: a pair of ConflictLists: (not_selected, selected)
1534.10.25 by Aaron Bentley
Move select_conflicts into ConflictList
239
        """
240
        path_set = set(paths)
241
        ids = {}
242
        selected_paths = set()
243
        new_conflicts = ConflictList()
244
        selected_conflicts = ConflictList()
245
        for path in paths:
246
            file_id = tree.path2id(path)
247
            if file_id is not None:
248
                ids[file_id] = path
249
250
        for conflict in self:
251
            selected = False
252
            for key in ('path', 'conflict_path'):
253
                cpath = getattr(conflict, key, None)
254
                if cpath is None:
255
                    continue
256
                if cpath in path_set:
257
                    selected = True
258
                    selected_paths.add(cpath)
259
            for key in ('file_id', 'conflict_file_id'):
260
                cfile_id = getattr(conflict, key, None)
261
                if cfile_id is None:
262
                    continue
263
                try:
264
                    cpath = ids[cfile_id]
265
                except KeyError:
266
                    continue
267
                selected = True
268
                selected_paths.add(cpath)
269
            if selected:
270
                selected_conflicts.append(conflict)
271
            else:
272
                new_conflicts.append(conflict)
273
        if ignore_misses is not True:
274
            for path in [p for p in paths if p not in selected_paths]:
275
                if not os.path.exists(tree.abspath(path)):
276
                    print "%s does not exist" % path
277
                else:
278
                    print "%s is not conflicted" % path
279
        return new_conflicts, selected_conflicts
280
281
 
1534.10.18 by Aaron Bentley
Defined all new Conflict types
282
class Conflict(object):
283
    """Base class for all types of conflict"""
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
284
285
    has_files = False
286
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
287
    def __init__(self, path, file_id=None):
1534.10.18 by Aaron Bentley
Defined all new Conflict types
288
        self.path = path
2309.4.13 by John Arbash Meinel
Conflicts go through Stanza so the need to be aware of utf8 versus unicode file ids.
289
        # warn turned off, because the factory blindly transfers the Stanza
290
        # values to __init__ and Stanza is purely a Unicode api.
291
        self.file_id = osutils.safe_file_id(file_id, warn=False)
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
292
293
    def as_stanza(self):
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
294
        s = rio.Stanza(type=self.typestring, path=self.path)
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
295
        if self.file_id is not None:
2309.4.13 by John Arbash Meinel
Conflicts go through Stanza so the need to be aware of utf8 versus unicode file ids.
296
            # Stanza requires Unicode apis
297
            s.add('file_id', self.file_id.decode('utf8'))
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
298
        return s
299
1534.10.22 by Aaron Bentley
Got ConflictList implemented
300
    def _cmp_list(self):
301
        return [type(self), self.path, self.file_id]
302
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
303
    def __cmp__(self, other):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
304
        if getattr(other, "_cmp_list", None) is None:
305
            return -1
306
        return cmp(self._cmp_list(), other._cmp_list())
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
307
1551.7.11 by Aaron Bentley
Add WorkingTree.add_conflicts
308
    def __hash__(self):
309
        return hash((type(self), self.path, self.file_id))
310
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
311
    def __eq__(self, other):
312
        return self.__cmp__(other) == 0
313
314
    def __ne__(self, other):
315
        return not self.__eq__(other)
1534.10.18 by Aaron Bentley
Defined all new Conflict types
316
1534.10.20 by Aaron Bentley
Got all tests passing
317
    def __str__(self):
318
        return self.format % self.__dict__
319
1534.10.22 by Aaron Bentley
Got ConflictList implemented
320
    def __repr__(self):
321
        rdict = dict(self.__dict__)
322
        rdict['class'] = self.__class__.__name__
323
        return self.rformat % rdict
324
1534.10.18 by Aaron Bentley
Defined all new Conflict types
325
    @staticmethod
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
326
    def factory(type, **kwargs):
1534.10.18 by Aaron Bentley
Defined all new Conflict types
327
        global ctype
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
328
        return ctype[type](**kwargs)
1534.10.18 by Aaron Bentley
Defined all new Conflict types
329
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
330
    @staticmethod
331
    def sort_key(conflict):
332
        if conflict.path is not None:
333
            return conflict.path, conflict.typestring
334
        elif getattr(conflict, "conflict_path", None) is not None:
335
            return conflict.conflict_path, conflict.typestring
336
        else:
337
            return None, conflict.typestring
338
1534.10.18 by Aaron Bentley
Defined all new Conflict types
339
340
class PathConflict(Conflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
341
    """A conflict was encountered merging file paths"""
342
1534.10.18 by Aaron Bentley
Defined all new Conflict types
343
    typestring = 'path conflict'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
344
1534.10.20 by Aaron Bentley
Got all tests passing
345
    format = 'Path conflict: %(path)s / %(conflict_path)s'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
346
347
    rformat = '%(class)s(%(path)r, %(conflict_path)r, %(file_id)r)'
1534.10.20 by Aaron Bentley
Got all tests passing
348
    def __init__(self, path, conflict_path=None, file_id=None):
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
349
        Conflict.__init__(self, path, file_id)
1534.10.18 by Aaron Bentley
Defined all new Conflict types
350
        self.conflict_path = conflict_path
351
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
352
    def as_stanza(self):
353
        s = Conflict.as_stanza(self)
1534.10.20 by Aaron Bentley
Got all tests passing
354
        if self.conflict_path is not None:
355
            s.add('conflict_path', self.conflict_path)
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
356
        return s
357
1534.10.20 by Aaron Bentley
Got all tests passing
358
359
class ContentsConflict(PathConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
360
    """The files are of different types, or not present"""
361
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
362
    has_files = True
363
1534.10.20 by Aaron Bentley
Got all tests passing
364
    typestring = 'contents conflict'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
365
1534.10.20 by Aaron Bentley
Got all tests passing
366
    format = 'Contents conflict in %(path)s'
367
368
369
class TextConflict(PathConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
370
    """The merge algorithm could not resolve all differences encountered."""
371
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
372
    has_files = True
373
1534.10.20 by Aaron Bentley
Got all tests passing
374
    typestring = 'text conflict'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
375
1534.10.20 by Aaron Bentley
Got all tests passing
376
    format = 'Text conflict in %(path)s'
377
378
1534.10.18 by Aaron Bentley
Defined all new Conflict types
379
class HandledConflict(Conflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
380
    """A path problem that has been provisionally resolved.
381
    This is intended to be a base class.
382
    """
383
384
    rformat = "%(class)s(%(action)r, %(path)r, %(file_id)r)"
385
    
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
386
    def __init__(self, action, path, file_id=None):
387
        Conflict.__init__(self, path, file_id)
1534.10.18 by Aaron Bentley
Defined all new Conflict types
388
        self.action = action
389
1534.10.22 by Aaron Bentley
Got ConflictList implemented
390
    def _cmp_list(self):
391
        return Conflict._cmp_list(self) + [self.action]
392
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
393
    def as_stanza(self):
394
        s = Conflict.as_stanza(self)
395
        s.add('action', self.action)
396
        return s
397
1534.10.20 by Aaron Bentley
Got all tests passing
398
1534.10.18 by Aaron Bentley
Defined all new Conflict types
399
class HandledPathConflict(HandledConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
400
    """A provisionally-resolved path problem involving two paths.
401
    This is intended to be a base class.
402
    """
403
404
    rformat = "%(class)s(%(action)r, %(path)r, %(conflict_path)r,"\
405
        " %(file_id)r, %(conflict_file_id)r)"
406
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
407
    def __init__(self, action, path, conflict_path, file_id=None,
1534.10.18 by Aaron Bentley
Defined all new Conflict types
408
                 conflict_file_id=None):
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
409
        HandledConflict.__init__(self, action, path, file_id)
1534.10.18 by Aaron Bentley
Defined all new Conflict types
410
        self.conflict_path = conflict_path 
2309.4.13 by John Arbash Meinel
Conflicts go through Stanza so the need to be aware of utf8 versus unicode file ids.
411
        # warn turned off, because the factory blindly transfers the Stanza
412
        # values to __init__.
413
        self.conflict_file_id = osutils.safe_file_id(conflict_file_id,
414
                                                     warn=False)
1534.10.18 by Aaron Bentley
Defined all new Conflict types
415
        
1534.10.22 by Aaron Bentley
Got ConflictList implemented
416
    def _cmp_list(self):
417
        return HandledConflict._cmp_list(self) + [self.conflict_path, 
418
                                                  self.conflict_file_id]
419
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
420
    def as_stanza(self):
421
        s = HandledConflict.as_stanza(self)
422
        s.add('conflict_path', self.conflict_path)
423
        if self.conflict_file_id is not None:
2309.4.13 by John Arbash Meinel
Conflicts go through Stanza so the need to be aware of utf8 versus unicode file ids.
424
            s.add('conflict_file_id', self.conflict_file_id.decode('utf8'))
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
425
            
426
        return s
1534.10.20 by Aaron Bentley
Got all tests passing
427
428
1534.10.18 by Aaron Bentley
Defined all new Conflict types
429
class DuplicateID(HandledPathConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
430
    """Two files want the same file_id."""
431
1534.10.18 by Aaron Bentley
Defined all new Conflict types
432
    typestring = 'duplicate id'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
433
1534.10.20 by Aaron Bentley
Got all tests passing
434
    format = 'Conflict adding id to %(conflict_path)s.  %(action)s %(path)s.'
435
1534.10.18 by Aaron Bentley
Defined all new Conflict types
436
437
class DuplicateEntry(HandledPathConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
438
    """Two directory entries want to have the same name."""
439
1534.10.18 by Aaron Bentley
Defined all new Conflict types
440
    typestring = 'duplicate'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
441
1534.10.20 by Aaron Bentley
Got all tests passing
442
    format = 'Conflict adding file %(conflict_path)s.  %(action)s %(path)s.'
443
1534.10.18 by Aaron Bentley
Defined all new Conflict types
444
445
class ParentLoop(HandledPathConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
446
    """An attempt to create an infinitely-looping directory structure.
447
    This is rare, but can be produced like so:
448
449
    tree A:
450
      mv foo/bar
451
    tree B:
452
      mv bar/foo
453
    merge A and B
454
    """
455
1534.10.18 by Aaron Bentley
Defined all new Conflict types
456
    typestring = 'parent loop'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
457
1534.10.20 by Aaron Bentley
Got all tests passing
458
    format = 'Conflict moving %(conflict_path)s into %(path)s.  %(action)s.'
459
1534.10.18 by Aaron Bentley
Defined all new Conflict types
460
461
class UnversionedParent(HandledConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
462
    """An attempt to version an file whose parent directory is not versioned.
463
    Typically, the result of a merge where one tree unversioned the directory
464
    and the other added a versioned file to it.
465
    """
466
1534.10.18 by Aaron Bentley
Defined all new Conflict types
467
    typestring = 'unversioned parent'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
468
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
469
    format = 'Conflict because %(path)s is not versioned, but has versioned'\
470
             ' children.  %(action)s.'
1534.10.20 by Aaron Bentley
Got all tests passing
471
1534.10.18 by Aaron Bentley
Defined all new Conflict types
472
473
class MissingParent(HandledConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
474
    """An attempt to add files to a directory that is not present.
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
475
    Typically, the result of a merge where THIS deleted the directory and
476
    the OTHER added a file to it.
477
    See also: DeletingParent (same situation, reversed THIS and OTHER)
1534.10.22 by Aaron Bentley
Got ConflictList implemented
478
    """
479
1534.10.18 by Aaron Bentley
Defined all new Conflict types
480
    typestring = 'missing parent'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
481
1534.10.20 by Aaron Bentley
Got all tests passing
482
    format = 'Conflict adding files to %(path)s.  %(action)s.'
483
484
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
485
class DeletingParent(HandledConflict):
486
    """An attempt to add files to a directory that is not present.
487
    Typically, the result of a merge where one OTHER deleted the directory and
488
    the THIS added a file to it.
489
    """
490
491
    typestring = 'deleting parent'
492
1551.8.23 by Aaron Bentley
Tweaked conflict message to be more understandable
493
    format = "Conflict: can't delete %(path)s because it is not empty.  "\
494
             "%(action)s."
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
495
1534.10.18 by Aaron Bentley
Defined all new Conflict types
496
497
ctype = {}
1534.10.20 by Aaron Bentley
Got all tests passing
498
499
1534.10.18 by Aaron Bentley
Defined all new Conflict types
500
def register_types(*conflict_types):
501
    """Register a Conflict subclass for serialization purposes"""
502
    global ctype
503
    for conflict_type in conflict_types:
504
        ctype[conflict_type.typestring] = conflict_type
505
1534.10.20 by Aaron Bentley
Got all tests passing
506
1534.10.18 by Aaron Bentley
Defined all new Conflict types
507
register_types(ContentsConflict, TextConflict, PathConflict, DuplicateID,
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
508
               DuplicateEntry, ParentLoop, UnversionedParent, MissingParent,
509
               DeletingParent,)