/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
    """
1551.9.8 by Aaron Bentley
Add --text parameter to conflicts
59
    takes_options = [Option('text', help='list text conflicts by pathname')]
60
61
    def run(self, text=False):
1534.10.6 by Aaron Bentley
Conflict serialization working for WorkingTree3
62
        from bzrlib.workingtree import WorkingTree
1534.10.9 by Aaron Bentley
Switched display functions to conflict_lines
63
        wt = WorkingTree.open_containing(u'.')[0]
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
64
        for conflict in wt.conflicts():
1551.9.8 by Aaron Bentley
Add --text parameter to conflicts
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')
1185.14.3 by Aaron Bentley
Copied conflict lister in
71
1652.1.1 by Martin Pool
Fix 'bzr resolve' run from subdirectory
72
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
73
class cmd_resolve(commands.Command):
1185.14.3 by Aaron Bentley
Copied conflict lister in
74
    """Mark a conflict as resolved.
1551.2.18 by Aaron Bentley
Updated docs to clarify conflict handling
75
76
    Merge will do its best to combine the changes in two branches, but there
77
    are some kinds of problems only a human can fix.  When it encounters those,
78
    it will mark a conflict.  A conflict means that you need to fix something,
79
    before you should commit.
80
2120.7.3 by Aaron Bentley
Update resolve command to automatically mark conflicts as 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.
1551.2.18 by Aaron Bentley
Updated docs to clarify conflict handling
84
85
    See also bzr conflicts.
1185.14.3 by Aaron Bentley
Copied conflict lister in
86
    """
1185.33.24 by Martin Pool
Add alias 'resolved'
87
    aliases = ['resolved']
1185.14.3 by Aaron Bentley
Copied conflict lister in
88
    takes_args = ['file*']
1551.2.18 by Aaron Bentley
Updated docs to clarify conflict handling
89
    takes_options = [Option('all', help='Resolve all conflicts in this tree')]
1185.14.3 by Aaron Bentley
Copied conflict lister in
90
    def run(self, file_list=None, all=False):
1534.10.6 by Aaron Bentley
Conflict serialization working for WorkingTree3
91
        from bzrlib.workingtree import WorkingTree
1652.1.3 by Martin Pool
Improved bzr resolve command line handling
92
        if all:
93
            if file_list:
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
94
                raise errors.BzrCommandError("If --all is specified,"
95
                                             " no FILE may be provided")
1652.1.3 by Martin Pool
Improved bzr resolve command line handling
96
            tree = WorkingTree.open_containing('.')[0]
97
            resolve(tree)
1185.14.3 by Aaron Bentley
Copied conflict lister in
98
        else:
2120.7.3 by Aaron Bentley
Update resolve command to automatically mark conflicts as resolved
99
            tree, file_list = builtins.tree_files(file_list)
1652.1.3 by Martin Pool
Improved bzr resolve command line handling
100
            if file_list is None:
2120.7.3 by Aaron Bentley
Update resolve command to automatically mark conflicts as resolved
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:
2120.7.4 by Aaron Bentley
Fix normal resolve
112
                resolve(tree, file_list)
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
113
114
1534.10.15 by Aaron Bentley
Revert does resolve
115
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
116
    tree.lock_tree_write()
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
117
    try:
1534.10.23 by Aaron Bentley
Removed conflicts_to_stanzas and stanzas_to_conflicts
118
        tree_conflicts = tree.conflicts()
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
119
        if paths is None:
1534.10.25 by Aaron Bentley
Move select_conflicts into ConflictList
120
            new_conflicts = ConflictList()
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
121
            selected_conflicts = tree_conflicts
122
        else:
123
            new_conflicts, selected_conflicts = \
1534.10.25 by Aaron Bentley
Move select_conflicts into ConflictList
124
                tree_conflicts.select_conflicts(tree, paths, ignore_misses)
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
125
        try:
1534.10.25 by Aaron Bentley
Move select_conflicts into ConflictList
126
            tree.set_conflicts(new_conflicts)
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
127
        except errors.UnsupportedOperation:
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
128
            pass
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
129
        selected_conflicts.remove_files(tree)
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
130
    finally:
131
        tree.unlock()
132
133
1185.35.1 by Aaron Bentley
Implemented conflicts.restore
134
def restore(filename):
135
    """\
136
    Restore a conflicted file to the state it was in before merging.
137
    Only text restoration supported at present.
138
    """
139
    conflicted = False
140
    try:
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
141
        osutils.rename(filename + ".THIS", filename)
1185.35.1 by Aaron Bentley
Implemented conflicts.restore
142
        conflicted = True
143
    except OSError, e:
144
        if e.errno != errno.ENOENT:
145
            raise
146
    try:
147
        os.unlink(filename + ".BASE")
148
        conflicted = True
149
    except OSError, e:
150
        if e.errno != errno.ENOENT:
151
            raise
152
    try:
153
        os.unlink(filename + ".OTHER")
154
        conflicted = True
155
    except OSError, e:
156
        if e.errno != errno.ENOENT:
157
            raise
158
    if not conflicted:
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
159
        raise errors.NotConflicted(filename)
1534.10.4 by Aaron Bentley
Implemented conflict serialization
160
161
1534.10.22 by Aaron Bentley
Got ConflictList implemented
162
class ConflictList(object):
1652.1.1 by Martin Pool
Fix 'bzr resolve' run from subdirectory
163
    """List of conflicts.
164
165
    Typically obtained from WorkingTree.conflicts()
166
1534.10.22 by Aaron Bentley
Got ConflictList implemented
167
    Can be instantiated from stanzas or from Conflict subclasses.
168
    """
169
170
    def __init__(self, conflicts=None):
171
        object.__init__(self)
172
        if conflicts is None:
173
            self.__list = []
174
        else:
175
            self.__list = conflicts
176
1652.1.1 by Martin Pool
Fix 'bzr resolve' run from subdirectory
177
    def is_empty(self):
178
        return len(self.__list) == 0
179
1534.10.22 by Aaron Bentley
Got ConflictList implemented
180
    def __len__(self):
181
        return len(self.__list)
182
183
    def __iter__(self):
184
        return iter(self.__list)
185
186
    def __getitem__(self, key):
187
        return self.__list[key]
188
189
    def append(self, conflict):
190
        return self.__list.append(conflict)
191
192
    def __eq__(self, other_list):
193
        return list(self) == list(other_list)
194
195
    def __ne__(self, other_list):
196
        return not (self == other_list)
197
198
    def __repr__(self):
199
        return "ConflictList(%r)" % self.__list
200
201
    @staticmethod
202
    def from_stanzas(stanzas):
203
        """Produce a new ConflictList from an iterable of stanzas"""
204
        conflicts = ConflictList()
205
        for stanza in stanzas:
206
            conflicts.append(Conflict.factory(**stanza.as_dict()))
207
        return conflicts
208
209
    def to_stanzas(self):
210
        """Generator of stanzas"""
211
        for conflict in self:
212
            yield conflict.as_stanza()
213
            
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
214
    def to_strings(self):
215
        """Generate strings for the provided conflicts"""
216
        for conflict in self:
217
            yield str(conflict)
218
219
    def remove_files(self, tree):
1534.10.25 by Aaron Bentley
Move select_conflicts into ConflictList
220
        """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
221
        for conflict in self:
222
            if not conflict.has_files:
223
                continue
224
            for suffix in CONFLICT_SUFFIXES:
225
                try:
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
226
                    osutils.delete_any(tree.abspath(conflict.path+suffix))
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
227
                except OSError, e:
228
                    if e.errno != errno.ENOENT:
229
                        raise
1534.10.21 by Aaron Bentley
Moved and renamed conflict functions
230
1534.10.25 by Aaron Bentley
Move select_conflicts into ConflictList
231
    def select_conflicts(self, tree, paths, ignore_misses=False):
232
        """Select the conflicts associated with paths in a tree.
233
        
234
        File-ids are also used for this.
1551.7.10 by Aaron Bentley
Remerge doesn't clear unrelated conflicts
235
        :return: a pair of ConflictLists: (not_selected, selected)
1534.10.25 by Aaron Bentley
Move select_conflicts into ConflictList
236
        """
237
        path_set = set(paths)
238
        ids = {}
239
        selected_paths = set()
240
        new_conflicts = ConflictList()
241
        selected_conflicts = ConflictList()
242
        for path in paths:
243
            file_id = tree.path2id(path)
244
            if file_id is not None:
245
                ids[file_id] = path
246
247
        for conflict in self:
248
            selected = False
249
            for key in ('path', 'conflict_path'):
250
                cpath = getattr(conflict, key, None)
251
                if cpath is None:
252
                    continue
253
                if cpath in path_set:
254
                    selected = True
255
                    selected_paths.add(cpath)
256
            for key in ('file_id', 'conflict_file_id'):
257
                cfile_id = getattr(conflict, key, None)
258
                if cfile_id is None:
259
                    continue
260
                try:
261
                    cpath = ids[cfile_id]
262
                except KeyError:
263
                    continue
264
                selected = True
265
                selected_paths.add(cpath)
266
            if selected:
267
                selected_conflicts.append(conflict)
268
            else:
269
                new_conflicts.append(conflict)
270
        if ignore_misses is not True:
271
            for path in [p for p in paths if p not in selected_paths]:
272
                if not os.path.exists(tree.abspath(path)):
273
                    print "%s does not exist" % path
274
                else:
275
                    print "%s is not conflicted" % path
276
        return new_conflicts, selected_conflicts
277
278
 
1534.10.18 by Aaron Bentley
Defined all new Conflict types
279
class Conflict(object):
280
    """Base class for all types of conflict"""
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
281
282
    has_files = False
283
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
284
    def __init__(self, path, file_id=None):
1534.10.18 by Aaron Bentley
Defined all new Conflict types
285
        self.path = path
286
        self.file_id = file_id
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
287
288
    def as_stanza(self):
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
289
        s = rio.Stanza(type=self.typestring, path=self.path)
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
290
        if self.file_id is not None:
291
            s.add('file_id', self.file_id)
292
        return s
293
1534.10.22 by Aaron Bentley
Got ConflictList implemented
294
    def _cmp_list(self):
295
        return [type(self), self.path, self.file_id]
296
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
297
    def __cmp__(self, other):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
298
        if getattr(other, "_cmp_list", None) is None:
299
            return -1
300
        return cmp(self._cmp_list(), other._cmp_list())
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
301
1551.7.11 by Aaron Bentley
Add WorkingTree.add_conflicts
302
    def __hash__(self):
303
        return hash((type(self), self.path, self.file_id))
304
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
305
    def __eq__(self, other):
306
        return self.__cmp__(other) == 0
307
308
    def __ne__(self, other):
309
        return not self.__eq__(other)
1534.10.18 by Aaron Bentley
Defined all new Conflict types
310
1534.10.20 by Aaron Bentley
Got all tests passing
311
    def __str__(self):
312
        return self.format % self.__dict__
313
1534.10.22 by Aaron Bentley
Got ConflictList implemented
314
    def __repr__(self):
315
        rdict = dict(self.__dict__)
316
        rdict['class'] = self.__class__.__name__
317
        return self.rformat % rdict
318
1534.10.18 by Aaron Bentley
Defined all new Conflict types
319
    @staticmethod
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
320
    def factory(type, **kwargs):
1534.10.18 by Aaron Bentley
Defined all new Conflict types
321
        global ctype
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
322
        return ctype[type](**kwargs)
1534.10.18 by Aaron Bentley
Defined all new Conflict types
323
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
324
    @staticmethod
325
    def sort_key(conflict):
326
        if conflict.path is not None:
327
            return conflict.path, conflict.typestring
328
        elif getattr(conflict, "conflict_path", None) is not None:
329
            return conflict.conflict_path, conflict.typestring
330
        else:
331
            return None, conflict.typestring
332
1534.10.18 by Aaron Bentley
Defined all new Conflict types
333
334
class PathConflict(Conflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
335
    """A conflict was encountered merging file paths"""
336
1534.10.18 by Aaron Bentley
Defined all new Conflict types
337
    typestring = 'path conflict'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
338
1534.10.20 by Aaron Bentley
Got all tests passing
339
    format = 'Path conflict: %(path)s / %(conflict_path)s'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
340
341
    rformat = '%(class)s(%(path)r, %(conflict_path)r, %(file_id)r)'
1534.10.20 by Aaron Bentley
Got all tests passing
342
    def __init__(self, path, conflict_path=None, file_id=None):
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
343
        Conflict.__init__(self, path, file_id)
1534.10.18 by Aaron Bentley
Defined all new Conflict types
344
        self.conflict_path = conflict_path
345
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
346
    def as_stanza(self):
347
        s = Conflict.as_stanza(self)
1534.10.20 by Aaron Bentley
Got all tests passing
348
        if self.conflict_path is not None:
349
            s.add('conflict_path', self.conflict_path)
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
350
        return s
351
1534.10.20 by Aaron Bentley
Got all tests passing
352
353
class ContentsConflict(PathConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
354
    """The files are of different types, or not present"""
355
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
356
    has_files = True
357
1534.10.20 by Aaron Bentley
Got all tests passing
358
    typestring = 'contents conflict'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
359
1534.10.20 by Aaron Bentley
Got all tests passing
360
    format = 'Contents conflict in %(path)s'
361
362
363
class TextConflict(PathConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
364
    """The merge algorithm could not resolve all differences encountered."""
365
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
366
    has_files = True
367
1534.10.20 by Aaron Bentley
Got all tests passing
368
    typestring = 'text conflict'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
369
1534.10.20 by Aaron Bentley
Got all tests passing
370
    format = 'Text conflict in %(path)s'
371
372
1534.10.18 by Aaron Bentley
Defined all new Conflict types
373
class HandledConflict(Conflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
374
    """A path problem that has been provisionally resolved.
375
    This is intended to be a base class.
376
    """
377
378
    rformat = "%(class)s(%(action)r, %(path)r, %(file_id)r)"
379
    
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
380
    def __init__(self, action, path, file_id=None):
381
        Conflict.__init__(self, path, file_id)
1534.10.18 by Aaron Bentley
Defined all new Conflict types
382
        self.action = action
383
1534.10.22 by Aaron Bentley
Got ConflictList implemented
384
    def _cmp_list(self):
385
        return Conflict._cmp_list(self) + [self.action]
386
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
387
    def as_stanza(self):
388
        s = Conflict.as_stanza(self)
389
        s.add('action', self.action)
390
        return s
391
1534.10.20 by Aaron Bentley
Got all tests passing
392
1534.10.18 by Aaron Bentley
Defined all new Conflict types
393
class HandledPathConflict(HandledConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
394
    """A provisionally-resolved path problem involving two paths.
395
    This is intended to be a base class.
396
    """
397
398
    rformat = "%(class)s(%(action)r, %(path)r, %(conflict_path)r,"\
399
        " %(file_id)r, %(conflict_file_id)r)"
400
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
401
    def __init__(self, action, path, conflict_path, file_id=None,
1534.10.18 by Aaron Bentley
Defined all new Conflict types
402
                 conflict_file_id=None):
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
403
        HandledConflict.__init__(self, action, path, file_id)
1534.10.18 by Aaron Bentley
Defined all new Conflict types
404
        self.conflict_path = conflict_path 
405
        self.conflict_file_id = conflict_file_id
406
        
1534.10.22 by Aaron Bentley
Got ConflictList implemented
407
    def _cmp_list(self):
408
        return HandledConflict._cmp_list(self) + [self.conflict_path, 
409
                                                  self.conflict_file_id]
410
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
411
    def as_stanza(self):
412
        s = HandledConflict.as_stanza(self)
413
        s.add('conflict_path', self.conflict_path)
414
        if self.conflict_file_id is not None:
415
            s.add('conflict_file_id', self.conflict_file_id)
416
            
417
        return s
1534.10.20 by Aaron Bentley
Got all tests passing
418
419
1534.10.18 by Aaron Bentley
Defined all new Conflict types
420
class DuplicateID(HandledPathConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
421
    """Two files want the same file_id."""
422
1534.10.18 by Aaron Bentley
Defined all new Conflict types
423
    typestring = 'duplicate id'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
424
1534.10.20 by Aaron Bentley
Got all tests passing
425
    format = 'Conflict adding id to %(conflict_path)s.  %(action)s %(path)s.'
426
1534.10.18 by Aaron Bentley
Defined all new Conflict types
427
428
class DuplicateEntry(HandledPathConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
429
    """Two directory entries want to have the same name."""
430
1534.10.18 by Aaron Bentley
Defined all new Conflict types
431
    typestring = 'duplicate'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
432
1534.10.20 by Aaron Bentley
Got all tests passing
433
    format = 'Conflict adding file %(conflict_path)s.  %(action)s %(path)s.'
434
1534.10.18 by Aaron Bentley
Defined all new Conflict types
435
436
class ParentLoop(HandledPathConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
437
    """An attempt to create an infinitely-looping directory structure.
438
    This is rare, but can be produced like so:
439
440
    tree A:
441
      mv foo/bar
442
    tree B:
443
      mv bar/foo
444
    merge A and B
445
    """
446
1534.10.18 by Aaron Bentley
Defined all new Conflict types
447
    typestring = 'parent loop'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
448
1534.10.20 by Aaron Bentley
Got all tests passing
449
    format = 'Conflict moving %(conflict_path)s into %(path)s.  %(action)s.'
450
1534.10.18 by Aaron Bentley
Defined all new Conflict types
451
452
class UnversionedParent(HandledConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
453
    """An attempt to version an file whose parent directory is not versioned.
454
    Typically, the result of a merge where one tree unversioned the directory
455
    and the other added a versioned file to it.
456
    """
457
1534.10.18 by Aaron Bentley
Defined all new Conflict types
458
    typestring = 'unversioned parent'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
459
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
460
    format = 'Conflict because %(path)s is not versioned, but has versioned'\
461
             ' children.  %(action)s.'
1534.10.20 by Aaron Bentley
Got all tests passing
462
1534.10.18 by Aaron Bentley
Defined all new Conflict types
463
464
class MissingParent(HandledConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
465
    """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
466
    Typically, the result of a merge where THIS deleted the directory and
467
    the OTHER added a file to it.
468
    See also: DeletingParent (same situation, reversed THIS and OTHER)
1534.10.22 by Aaron Bentley
Got ConflictList implemented
469
    """
470
1534.10.18 by Aaron Bentley
Defined all new Conflict types
471
    typestring = 'missing parent'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
472
1534.10.20 by Aaron Bentley
Got all tests passing
473
    format = 'Conflict adding files to %(path)s.  %(action)s.'
474
475
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
476
class DeletingParent(HandledConflict):
477
    """An attempt to add files to a directory that is not present.
478
    Typically, the result of a merge where one OTHER deleted the directory and
479
    the THIS added a file to it.
480
    """
481
482
    typestring = 'deleting parent'
483
1551.8.23 by Aaron Bentley
Tweaked conflict message to be more understandable
484
    format = "Conflict: can't delete %(path)s because it is not empty.  "\
485
             "%(action)s."
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
486
1534.10.18 by Aaron Bentley
Defined all new Conflict types
487
488
ctype = {}
1534.10.20 by Aaron Bentley
Got all tests passing
489
490
1534.10.18 by Aaron Bentley
Defined all new Conflict types
491
def register_types(*conflict_types):
492
    """Register a Conflict subclass for serialization purposes"""
493
    global ctype
494
    for conflict_type in conflict_types:
495
        ctype[conflict_type.typestring] = conflict_type
496
1534.10.20 by Aaron Bentley
Got all tests passing
497
1534.10.18 by Aaron Bentley
Defined all new Conflict types
498
register_types(ContentsConflict, TextConflict, PathConflict, DuplicateID,
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
499
               DuplicateEntry, ParentLoop, UnversionedParent, MissingParent,
500
               DeletingParent,)